From 140ad357463c767f442431dd5917e70c8d20a1ca Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 12:09:01 +0100 Subject: [PATCH 0001/2070] Add a test for wss proxy tunneling: Netty is fine but Grizzly isn't --- .../websocket/ProxyTunnellingTest.java | 123 ++++++++++++++++++ .../websocket/GrizzlyProxyTunnellingTest.java | 33 +++++ .../websocket/NettyProxyTunnellingTest.java | 28 ++++ 3 files changed, 184 insertions(+) create mode 100644 api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java create mode 100644 providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java create mode 100644 providers/netty/src/test/java/org/asynchttpclient/providers/netty/websocket/NettyProxyTunnellingTest.java diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java new file mode 100644 index 0000000000..b9d8c89265 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.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 org.asynchttpclient.websocket; + +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; +import static org.testng.Assert.assertEquals; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.ProxyServer; +import org.eclipse.jetty.proxy.ConnectHandler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.websocket.server.WebSocketHandler; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Proxy usage tests. + */ +public abstract class ProxyTunnellingTest extends AbstractBasicTest { + + private Server server2; + + @BeforeClass(alwaysRun = true) + public void setUpGlobal() throws Exception { + port1 = findFreePort(); + server = newJettyHttpServer(port1); + server.setHandler(new ConnectHandler()); + server.start(); + + port2 = findFreePort(); + + server2 = newJettyHttpsServer(port2); + server2.setHandler(getWebSocketHandler()); + server2.start(); + + logger.info("Local HTTP server started successfully"); + } + + @Override + public WebSocketHandler getWebSocketHandler() { + return new WebSocketHandler() { + @Override + public void configure(WebSocketServletFactory factory) { + factory.register(EchoSocket.class); + } + }; + } + + @AfterClass(alwaysRun = true) + public void tearDownGlobal() throws Exception { + server.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/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java new file mode 100644 index 0000000000..6d69758e71 --- /dev/null +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.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 org.asynchttpclient.providers.grizzly.websocket; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.grizzly.GrizzlyProviderUtil; +import org.asynchttpclient.websocket.ProxyTunnellingTest; +import org.testng.annotations.Test; + +@Test +public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return GrizzlyProviderUtil.grizzlyProvider(config); + } + + @Test(timeOut = 60000, enabled = false) + public void echoText() throws Exception { + // FIXME + } +} diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/websocket/NettyProxyTunnellingTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/websocket/NettyProxyTunnellingTest.java new file mode 100644 index 0000000000..2ce2156d96 --- /dev/null +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/websocket/NettyProxyTunnellingTest.java @@ -0,0 +1,28 @@ +/* + * 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 org.asynchttpclient.providers.netty.websocket; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.NettyProviderUtil; +import org.asynchttpclient.websocket.ProxyTunnellingTest; +import org.testng.annotations.Test; + +@Test +public class NettyProxyTunnellingTest extends ProxyTunnellingTest { + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return NettyProviderUtil.nettyProvider(config); + } +} From 05e3a9e87b663d3fc13307754cd4b396d37704c0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 12:09:08 +0100 Subject: [PATCH 0002/2070] minor clean up --- .../providers/grizzly/websocket/GrizzlyRedirectTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyRedirectTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyRedirectTest.java index 8600b57bbe..d01f2424dc 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyRedirectTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyRedirectTest.java @@ -15,8 +15,6 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; -import org.asynchttpclient.providers.grizzly.GrizzlyProviderUtil; import org.asynchttpclient.providers.grizzly.GrizzlyProviderUtil; import org.asynchttpclient.websocket.RedirectTest; From 341e1548e162fab2a006a46fcf5335c5a1e455e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Feb 2014 17:45:44 +0100 Subject: [PATCH 0003/2070] Remove dead code --- api/src/main/java/org/asynchttpclient/Realm.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 85bcff15e4..ecf0c6ed1d 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -413,19 +413,6 @@ 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; From 840dbb2e0dc60d5c73dbbc0c67c90fd35e0b9bde Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Feb 2014 18:12:16 +0100 Subject: [PATCH 0004/2070] Have Netty provider use parseProxyAuthenticateHeader, just like Grizzly one --- .../main/java/org/asynchttpclient/Realm.java | 58 +++++++++++++------ .../providers/netty/handler/HttpProtocol.java | 21 ++++--- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index ecf0c6ed1d..496da9d198 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -55,10 +55,8 @@ public enum AuthScheme { DIGEST, BASIC, NTLM, SPNEGO, KERBEROS, NONE } - private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, - String algorithm, String response, String qop, String nc, String cnonce, String uri, String method, - boolean usePreemptiveAuth, String domain, String enc, String host, boolean messageType2Received, - String opaque) { + private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, String qop, String nc, String cnonce, + String uri, String method, boolean usePreemptiveAuth, String domain, String enc, String host, boolean messageType2Received, String opaque) { this.principal = principal; this.password = password; @@ -214,10 +212,9 @@ public boolean equals(Object o) { @Override public String toString() { - return "Realm{" + "principal='" + principal + '\'' + ", scheme=" + scheme - + ", realmName='" + realmName + '\'' + ", nonce='" + nonce + '\'' + ", algorithm='" + algorithm + '\'' - + ", response='" + response + '\'' + ", qop='" + qop + '\'' + ", nc='" + nc + '\'' + ", cnonce='" - + cnonce + '\'' + ", uri='" + uri + '\'' + ", methodName='" + methodName + '\'' + '}'; + return "Realm{" + "principal='" + principal + '\'' + ", scheme=" + scheme + ", realmName='" + realmName + '\'' + ", nonce='" + nonce + '\'' + ", algorithm='" + algorithm + + '\'' + ", response='" + response + '\'' + ", qop='" + qop + '\'' + ", nc='" + nc + '\'' + ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' + + ", methodName='" + methodName + '\'' + '}'; } @Override @@ -413,6 +410,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; @@ -464,8 +474,8 @@ private String match(String headerLine, String token) { match += token.length() + 1; int traillingComa = headerLine.indexOf(",", match); String value = headerLine.substring(match, traillingComa > 0 ? traillingComa : headerLine.length()); - value = value.endsWith("\"") ? value.substring(0, value.length() - 1) : value; - return value.startsWith("\"") ? value.substring(1) : value; + value = value.length() > 0 && value.charAt(value.length() - 1) == '"' ? value.substring(0, value.length() - 1) : value; + return value.charAt(0) == '"' ? value.substring(1) : value; } public String getEncoding() { @@ -484,24 +494,34 @@ private void newResponse() { } catch (NoSuchAlgorithmException e) { throw new SecurityException(e); } - md.update(new StringBuilder(principal).append(":").append(realmName).append(":").append(password) - .toString().getBytes(StandardCharsets.ISO_8859_1)); + md.update(new StringBuilder(principal).append(":")// + .append(realmName).append(":")// + .append(password).toString()// + .getBytes(StandardCharsets.ISO_8859_1)); 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(StandardCharsets.ISO_8859_1)); + md.update(new StringBuilder(methodName).append(':')// + .append(uri).toString()// + .getBytes(StandardCharsets.ISO_8859_1)); byte[] ha2 = md.digest(); if (qop == null || qop.length() == 0) { - md.update(new StringBuilder(toBase16(ha1)).append(':').append(nonce).append(':').append(toBase16(ha2)) - .toString().getBytes(StandardCharsets.ISO_8859_1)); + md.update(new StringBuilder(toBase16(ha1)).append(':')// + .append(nonce).append(':')// + .append(toBase16(ha2)).toString()// + .getBytes(StandardCharsets.ISO_8859_1)); } else { // qop ="auth" or "auth-int" - md.update(new StringBuilder(toBase16(ha1)).append(':').append(nonce).append(':').append(NC).append(':') - .append(cnonce).append(':').append(qop).append(':').append(toBase16(ha2)).toString() + md.update(new StringBuilder(toBase16(ha1)).append(':')// + .append(nonce).append(':')// + .append(NC).append(':')// + .append(cnonce).append(':')// + .append(qop).append(':')// + .append(toBase16(ha2)).toString()// .getBytes(StandardCharsets.ISO_8859_1)); } @@ -549,8 +569,8 @@ public Realm build() { newResponse(); } - return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, - methodName, usePreemptive, domain, enc, host, messageType2Received, opaque); + return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName, usePreemptive, domain, enc, host, + messageType2Received, opaque); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 4b76594562..20d93aed94 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -102,7 +102,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader) { headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); } - + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { @@ -278,7 +278,13 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode, Realm r if (newRealm == null) return true; } else { - newRealm = future.getRequest().getRealm(); + newRealm = new Realm.RealmBuilder().clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri("/")// + .setMethodName(HttpMethod.CONNECT.name())// + .setUsePreemptiveAuth(true)// + .parseProxyAuthenticateHeader(proxyAuthenticateHeaders.get(0))// + .build(); } future.setReuseChannel(true); @@ -315,8 +321,8 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques return false; } - private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, - HttpResponseHeaders responseHeaders, HttpResponse response) throws Exception { + private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, HttpResponseHeaders responseHeaders, + HttpResponse response) throws Exception { if (!future.getAndSetStatusReceived(true) && (handler.onStatusReceived(status) != STATE.CONTINUE || handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE)) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; @@ -324,8 +330,8 @@ private boolean handleHanderAndExit(Channel channel, NettyResponseFuture futu return false; } - private boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, HttpRequest httpRequest, - ProxyServer proxyServer, HttpResponse response) throws Exception { + private boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, HttpRequest httpRequest, ProxyServer proxyServer, + HttpResponse response) throws Exception { // store the original headers so we can re-send all them to // the handler in case of trailing headers @@ -406,8 +412,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f } } } catch (Exception t) { - if (hasIOExceptionFilters && t instanceof IOException - && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { + if (hasIOExceptionFilters && t instanceof IOException && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { return; } From 2fd0f67efbce63dfa2f470f00645f99893873c6b Mon Sep 17 00:00:00 2001 From: Ray Tsang Date: Fri, 21 Feb 2014 01:56:12 +0100 Subject: [PATCH 0005/2070] Update pom.xml Upgrade to JDeferred 1.2.0 --- extras/jdeferred/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/jdeferred/pom.xml b/extras/jdeferred/pom.xml index af6ddab2ad..9945c60ad6 100644 --- a/extras/jdeferred/pom.xml +++ b/extras/jdeferred/pom.xml @@ -22,13 +22,13 @@ .. async-http-client-extras-jdeferred - Async Http Client jDeffered Extras + Async Http Client JDeferred Extras The Async Http Client jDeffered Extras. org.jdeferred jdeferred-core - 1.0.0 + 1.2.0 From 4e2d2c4ff5802cc8aa809760133dcb15f0c642fc Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 26 Feb 2014 14:31:02 -0500 Subject: [PATCH 0006/2070] Making contentLength a long to handle large files. --- .../asynchttpclient/resumable/ResumableAsyncHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index eac9ab6ea8..b43e806ae9 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -42,7 +42,7 @@ public class ResumableAsyncHandler implements AsyncHandler { private final static Logger logger = LoggerFactory.getLogger(TransferCompletionHandler.class); private final AtomicLong byteTransferred; - private Integer contentLength; + private Long contentLength; private String url; private final ResumableProcessor resumableProcessor; private final AsyncHandler decoratedAsyncHandler; @@ -180,8 +180,8 @@ 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) { + contentLength = Long.valueOf(contentLengthHeader); + if (contentLength == null || contentLength == -1L) { return AsyncHandler.STATE.ABORT; } } From f77c1b8e6e91776e272fde7d14b4e56e5376a3cb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:17:39 +0100 Subject: [PATCH 0007/2070] contentLength shouldn't be a member --- .../org/asynchttpclient/resumable/ResumableAsyncHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index b43e806ae9..119a55538d 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -42,7 +42,6 @@ public class ResumableAsyncHandler implements AsyncHandler { private final static Logger logger = LoggerFactory.getLogger(TransferCompletionHandler.class); private final AtomicLong byteTransferred; - private Long contentLength; private String url; private final ResumableProcessor resumableProcessor; private final AsyncHandler decoratedAsyncHandler; @@ -180,8 +179,7 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws responseBuilder.accumulate(headers); String contentLengthHeader = headers.getHeaders().getFirstValue("Content-Length"); if (contentLengthHeader != null) { - contentLength = Long.valueOf(contentLengthHeader); - if (contentLength == null || contentLength == -1L) { + if (Long.parseLong(contentLengthHeader) == -1L) { return AsyncHandler.STATE.ABORT; } } From 698e628afbc16da9b39a94b448964838b67c3dbe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:38:22 +0100 Subject: [PATCH 0008/2070] Fix Semaphore leak, port #488 on master --- .../netty/request/NettyRequestSender.java | 2 + .../netty/NettyConnectionPoolTest.java | 56 +++++++++++++++---- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 5694fe0c83..39a14726c8 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -230,6 +230,8 @@ private ListenableFuture sendRequestWithNewChannel(Request request, URI u if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { channels.registerChannel(channelFuture.channel()); connectListener.future().attachChannel(channelFuture.channel(), false); + } else if (acquiredConnection) { + channels.releaseFreeConnections(); } return connectListener.future(); } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java index fd2c76cee6..e675f9713f 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java @@ -1,26 +1,27 @@ /* - * 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. + * 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 org.asynchttpclient.providers.netty; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; 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 io.netty.channel.Channel; +import java.net.ConnectException; import java.util.concurrent.TimeUnit; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.Response; import org.asynchttpclient.async.ConnectionPoolTest; import org.asynchttpclient.providers.netty.channel.ChannelPool; import org.testng.annotations.Test; @@ -59,7 +60,8 @@ public void destroy() { NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); providerConfig.setChannelPool(cp); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() + .setAsyncHttpClientProviderConfig(providerConfig).build()); try { Exception exception = null; try { @@ -102,7 +104,8 @@ public void destroy() { NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); providerConfig.setChannelPool(cp); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() + .setAsyncHttpClientProviderConfig(providerConfig).build()); try { Exception exception = null; try { @@ -116,4 +119,33 @@ public void destroy() { client.close(); } } + + @Test + public void testHostNotContactable() { + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().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); + fail("Shouldn't be here: should get an exception instead"); + } catch (Exception ex) { + assertNotNull(ex.getCause()); + Throwable cause = ex.getCause(); + assertTrue(cause instanceof ConnectException); + } + } + } finally { + client.close(); + } + } } From d2fb86d723ed5ea146d6bee388189c85332ddabf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:38:28 +0100 Subject: [PATCH 0009/2070] Minor clean up --- .../asynchttpclient/async/MaxConnectionsInThreads.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java index 94e76c64e9..48aaad6e24 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java @@ -66,10 +66,7 @@ public void run() { // assert that 2nd request fails, because maxTotalConnections=1 // logger.debug(i); caughtError[0] = true; - System.err.println("============"); - e.printStackTrace(); - System.err.println("============"); - + logger.error("Exception ", e); } } }; @@ -81,8 +78,7 @@ public void run() { try { t.join(); } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + logger.error("Exception ", e); } } From 1ecb26991d5fbc3781bcbf05ecfcb50727e93aa7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:48:34 +0100 Subject: [PATCH 0010/2070] New organize import rules --- .../org/asynchttpclient/AsyncHttpClient.java | 19 +++---- .../AsyncHttpClientConfigBean.java | 1 + .../DefaultConnectionPoolStrategy.java | 4 +- .../java/org/asynchttpclient/ProxyServer.java | 6 +-- .../main/java/org/asynchttpclient/Realm.java | 4 +- .../java/org/asynchttpclient/Request.java | 6 +-- .../org/asynchttpclient/RequestBuilder.java | 6 +-- .../java/org/asynchttpclient/Response.java | 4 +- .../org/asynchttpclient/SSLEngineFactory.java | 1 + .../extra/AsyncHandlerWrapper.java | 4 +- .../extra/ThrottleRequestFilter.java | 6 +-- .../generators/InputStreamBodyGenerator.java | 8 +-- .../listener/TransferCompletionHandler.java | 4 +- .../multipart/AbstractFilePart.java | 4 +- .../asynchttpclient/multipart/FilePart.java | 6 +-- .../multipart/MultipartBody.java | 8 +-- .../multipart/MultipartUtils.java | 15 +++--- .../org/asynchttpclient/multipart/Part.java | 4 +- .../org/asynchttpclient/ntlm/NTLMEngine.java | 12 ++--- .../oauth/OAuthSignatureCalculator.java | 12 ++--- .../asynchttpclient/oauth/ThreadSafeHMAC.java | 6 +-- .../providers/ResponseBase.java | 8 +-- .../PropertiesBasedResumableProcessor.java | 1 - .../util/AsyncHttpProviderUtils.java | 10 ++-- .../util/AuthenticatorUtils.java | 6 +-- .../org/asynchttpclient/util/ProxyUtils.java | 16 +++--- .../org/asynchttpclient/util/SslUtils.java | 1 + .../java/org/asynchttpclient/RealmTest.java | 6 +-- .../async/AbstractBasicHttpsTest.java | 3 +- .../async/AbstractBasicTest.java | 4 +- .../async/AsyncProvidersBasicTest.java | 47 +++++++++-------- .../async/AsyncStreamHandlerTest.java | 25 +++++---- .../async/AsyncStreamLifecycleTest.java | 33 ++++++------ .../async/AuthTimeoutTest.java | 29 +++++++---- .../asynchttpclient/async/BasicAuthTest.java | 34 +++++++----- .../asynchttpclient/async/BasicHttpsTest.java | 24 +++++---- .../asynchttpclient/async/BodyChunkTest.java | 4 +- .../async/BodyDeferringAsyncHandlerTest.java | 30 ++++++----- .../async/ByteBufferCapacityTest.java | 26 +++++----- .../asynchttpclient/async/ChunkingTest.java | 12 +++-- .../async/ComplexClientTest.java | 4 +- .../async/ConnectionPoolTest.java | 21 ++++---- .../asynchttpclient/async/DigestAuthTest.java | 29 ++++++----- .../asynchttpclient/async/EmptyBodyTest.java | 14 ++--- .../async/ErrorResponseTest.java | 6 +-- .../async/Expect100ContinueTest.java | 20 +++---- .../async/FastUnauthorizedUploadTest.java | 14 ++--- .../async/FilePartLargeFileTest.java | 21 ++++---- .../org/asynchttpclient/async/FilterTest.java | 9 ++-- .../FluentCaseInsensitiveStringsMapTest.java | 8 +-- .../async/FluentStringsMapTest.java | 8 +-- .../asynchttpclient/async/Head302Test.java | 22 ++++---- .../async/HostnameVerifierTest.java | 35 +++++++------ .../async/HttpToHttpsRedirectTest.java | 24 +++++---- .../async/IdleStateHandlerTest.java | 17 +++--- .../async/InputStreamTest.java | 9 ++-- .../async/ListenableFutureTest.java | 4 +- .../async/MaxConnectionsInThreads.java | 29 ++++++----- .../async/MaxTotalConnectionTest.java | 5 +- .../async/MultipartUploadTest.java | 49 +++++++++-------- .../async/MultipleHeaderTest.java | 26 +++++----- .../async/NoNullResponseTest.java | 4 +- .../async/NonAsciiContentLengthTest.java | 25 ++++----- .../async/ParamEncodingTest.java | 9 ++-- .../async/PerRequestRelative302Test.java | 30 ++++++----- .../async/PerRequestTimeoutTest.java | 13 ++--- .../async/PostRedirectGetTest.java | 19 +++---- .../asynchttpclient/async/PostWithQSTest.java | 9 ++-- .../org/asynchttpclient/async/ProxyTest.java | 29 ++++++----- .../async/ProxyTunnellingTest.java | 14 ++--- .../async/PutLargeFileTest.java | 14 ++--- .../async/QueryParametersTest.java | 8 +-- .../org/asynchttpclient/async/RC10KTest.java | 30 ++++++----- .../async/RedirectConnectionUsageTest.java | 24 +++++---- .../async/Relative302Test.java | 30 ++++++----- .../asynchttpclient/async/RemoteSiteTest.java | 10 ++-- .../async/RequestBuilderTest.java | 4 +- .../async/RetryRequestTest.java | 6 ++- .../SimpleAsyncClientErrorBehaviourTest.java | 19 +++---- .../async/SimpleAsyncHttpClientTest.java | 24 +++++---- .../async/TransferListenerTest.java | 29 ++++++----- .../async/WebDavBasicTest.java | 12 +++-- .../async/ZeroCopyFileTest.java | 34 ++++++------ .../async/util/EchoHandler.java | 8 +-- .../asynchttpclient/async/util/TestUtils.java | 52 +++++++++---------- .../cookie/CookieDecoderTest.java | 2 - .../ByteArrayBodyGeneratorTest.java | 6 +-- .../multipart/MultipartBodyTest.java | 12 ++--- ...PropertiesBasedResumableProcesserTest.java | 5 +- .../resumable/ResumableAsyncHandlerTest.java | 7 ++- .../util/AsyncHttpProviderUtilsTest.java | 4 +- .../asynchttpclient/util/ProxyUtilsTest.java | 3 +- .../websocket/AbstractBasicTest.java | 3 +- .../websocket/ByteMessageTest.java | 6 +-- .../websocket/CloseCodeReasonMessageTest.java | 8 +-- .../asynchttpclient/websocket/EchoSocket.java | 6 +-- .../websocket/ProxyTunnellingTest.java | 6 +-- .../websocket/RedirectTest.java | 20 +++---- .../websocket/TextMessageTest.java | 10 ++-- .../extra/ListenableFutureAdapter.java | 4 +- .../RateLimitedThrottleRequestFilter.java | 6 +-- .../extra/AsyncHttpDeferredObject.java | 11 ++-- .../asynchttpclient/extra/AsyncHttpTest.java | 11 ++-- .../providers/grizzly/ConnectionManager.java | 4 +- .../providers/grizzly/EventHandler.java | 8 +-- .../grizzly/FeedableBodyGenerator.java | 14 +++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 20 +++---- .../providers/grizzly/GrizzlyResponse.java | 4 +- .../grizzly/GrizzlyResponseBodyPart.java | 1 - .../grizzly/GrizzlyResponseFuture.java | 1 - .../grizzly/GrizzlyResponseHeaders.java | 1 - .../grizzly/GrizzlyResponseStatus.java | 6 +-- .../providers/grizzly/HttpTxContext.java | 3 +- .../bodyhandler/ByteArrayBodyHandler.java | 1 - .../bodyhandler/ParamsBodyHandler.java | 4 +- .../grizzly/bodyhandler/PartsBodyHandler.java | 8 +-- .../bodyhandler/StreamDataBodyHandler.java | 4 +- .../filters/AsyncHttpClientFilter.java | 17 +++--- .../grizzly/filters/ProxyFilter.java | 8 +-- .../grizzly/filters/SwitchingSSLFilter.java | 1 + .../statushandler/AuthorizationHandler.java | 4 +- .../statushandler/RedirectHandler.java | 4 +- .../websocket/GrizzlyWebSocketAdapter.java | 4 +- .../grizzly/GrizzlyBasicAuthTest.java | 1 - .../grizzly/GrizzlyConnectionPoolTest.java | 6 ++- .../grizzly/GrizzlyProviderUtil.java | 1 - .../GrizzlyUnexpectingTimeoutTest.java | 25 +++++---- .../netty/NettyAsyncHttpProvider.java | 6 +-- .../netty/NettyAsyncHttpProviderConfig.java | 16 +++--- .../providers/netty/channel/Channels.java | 35 +++++++------ .../netty/channel/DefaultChannelPool.java | 13 ++--- .../netty/future/NettyResponseFuture.java | 27 +++++----- .../providers/netty/handler/HttpProtocol.java | 27 +++++----- .../providers/netty/handler/Processor.java | 22 ++++---- .../providers/netty/handler/Protocol.java | 15 +++--- .../netty/handler/WebSocketProtocol.java | 23 ++++---- .../netty/request/NettyConnectListener.java | 14 ++--- .../netty/request/NettyRequestFactory.java | 29 ++++++----- .../netty/request/NettyRequestSender.java | 29 ++++++----- .../netty/request/ProgressListener.java | 12 ++--- .../netty/request/body/BodyFileRegion.java | 4 +- .../request/body/FeedableBodyGenerator.java | 8 +-- .../netty/request/body/NettyBody.java | 6 +-- .../netty/request/body/NettyBodyBody.java | 16 +++--- .../request/body/NettyByteArrayBody.java | 6 +-- .../netty/request/body/NettyFileBody.java | 16 +++--- .../request/body/NettyInputStreamBody.java | 12 ++--- .../request/body/NettyMultipartBody.java | 4 +- .../IdleConnectionTimeoutTimerTask.java | 7 +-- .../timeout/RequestTimeoutTimerTask.java | 7 +-- .../request/timeout/TimeoutTimerTask.java | 10 ++-- .../netty/response/EagerResponseBodyPart.java | 4 +- .../netty/response/NettyResponse.java | 20 +++---- .../netty/response/ResponseHeaders.java | 6 +-- .../netty/response/ResponseStatus.java | 10 ++-- .../providers/netty/ws/NettyWebSocket.java | 9 ++-- .../providers/netty/ws/WebSocketUtil.java | 6 +-- .../netty/NettyAsyncProviderPipelineTest.java | 18 ++++--- .../netty/NettyAsyncResponseTest.java | 14 ++--- .../netty/NettyConnectionPoolTest.java | 9 ++-- .../netty/NettyPerRequestTimeoutTest.java | 2 +- .../NettyRequestThrottleTimeoutTest.java | 29 ++++++----- .../netty/RetryNonBlockingIssue.java | 32 ++++++------ 163 files changed, 1112 insertions(+), 980 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java index d7df7b7429..de5145c017 100755 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java @@ -16,6 +16,16 @@ */ package org.asynchttpclient; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.filter.FilterContext; +import org.asynchttpclient.filter.FilterException; +import org.asynchttpclient.filter.RequestFilter; +import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.resumable.ResumableAsyncHandler; +import org.eclipse.jetty.http.HttpContent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.Closeable; import java.io.IOException; import java.io.InputStream; @@ -27,15 +37,6 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.filter.FilterContext; -import org.asynchttpclient.filter.FilterException; -import org.asynchttpclient.filter.RequestFilter; -import org.asynchttpclient.multipart.Part; -import org.asynchttpclient.resumable.ResumableAsyncHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * This class support asynchronous and synchronous HTTP request. *

diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index db961ff63b..4f917df0cb 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -20,6 +20,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; diff --git a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java index 726e7dd2ed..2ae901ea80 100644 --- a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java +++ b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java @@ -15,10 +15,10 @@ */ package org.asynchttpclient; -import java.net.URI; - import org.asynchttpclient.util.AsyncHttpProviderUtils; +import java.net.URI; + public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { INSTANCE; diff --git a/api/src/main/java/org/asynchttpclient/ProxyServer.java b/api/src/main/java/org/asynchttpclient/ProxyServer.java index 9b5146c0b9..ba8de97018 100644 --- a/api/src/main/java/org/asynchttpclient/ProxyServer.java +++ b/api/src/main/java/org/asynchttpclient/ProxyServer.java @@ -16,15 +16,15 @@ */ package org.asynchttpclient; +import org.asynchttpclient.util.AsyncHttpProviderUtils; +import org.asynchttpclient.util.StandardCharsets; + import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.StandardCharsets; - /** * Represents a proxy server. */ diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 496da9d198..aea105fa0d 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -16,14 +16,14 @@ */ package org.asynchttpclient; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.util.StandardCharsets; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; - /** * This class is required when authentication is needed. The class support DIGEST and BASIC. */ diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 3b4deddc19..488b97b7ee 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -16,6 +16,9 @@ */ package org.asynchttpclient; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; + import java.io.File; import java.io.InputStream; import java.net.InetAddress; @@ -23,9 +26,6 @@ import java.util.Collection; import java.util.List; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.multipart.Part; - /** * The Request class can be used to construct HTTP request: *

diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilder.java b/api/src/main/java/org/asynchttpclient/RequestBuilder.java
index 25295b43ce..5718b37530 100644
--- a/api/src/main/java/org/asynchttpclient/RequestBuilder.java
+++ b/api/src/main/java/org/asynchttpclient/RequestBuilder.java
@@ -15,13 +15,13 @@
  */
 package org.asynchttpclient;
 
+import org.asynchttpclient.cookie.Cookie;
+import org.asynchttpclient.multipart.Part;
+
 import java.io.InputStream;
 import java.util.Collection;
 import java.util.Map;
 
-import org.asynchttpclient.cookie.Cookie;
-import org.asynchttpclient.multipart.Part;
-
 /**
  * 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/api/src/main/java/org/asynchttpclient/Response.java b/api/src/main/java/org/asynchttpclient/Response.java
index d20dbd7f69..998e883501 100644
--- a/api/src/main/java/org/asynchttpclient/Response.java
+++ b/api/src/main/java/org/asynchttpclient/Response.java
@@ -16,6 +16,8 @@
  */
 package org.asynchttpclient;
 
+import org.asynchttpclient.cookie.Cookie;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -24,8 +26,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.asynchttpclient.cookie.Cookie;
-
 /**
  * Represents the asynchronous HTTP response callback for an {@link AsyncCompletionHandler}
  */
diff --git a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java
index 394ab9bfe4..0289a0e109 100644
--- a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java
+++ b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java
@@ -16,6 +16,7 @@
 package org.asynchttpclient;
 
 import javax.net.ssl.SSLEngine;
+
 import java.security.GeneralSecurityException;
 
 /**
diff --git a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java
index a330dd00b2..3ff4d806f6 100644
--- a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java
+++ b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java
@@ -1,7 +1,5 @@
 package org.asynchttpclient.extra;
 
-import java.util.concurrent.Semaphore;
-
 import org.asynchttpclient.AsyncHandler;
 import org.asynchttpclient.HttpResponseBodyPart;
 import org.asynchttpclient.HttpResponseHeaders;
@@ -9,6 +7,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.concurrent.Semaphore;
+
 public class AsyncHandlerWrapper implements AsyncHandler {
 
 	private final static Logger logger = LoggerFactory.getLogger(AsyncHandlerWrapper.class);
diff --git a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java
index 186547b168..98dfd8c38d 100644
--- a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java
+++ b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java
@@ -12,15 +12,15 @@
  */
 package org.asynchttpclient.extra;
 
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
 import org.asynchttpclient.filter.FilterContext;
 import org.asynchttpclient.filter.FilterException;
 import org.asynchttpclient.filter.RequestFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 /**
  * A {@link org.asynchttpclient.filter.RequestFilter} throttles requests and block when the number of permits is reached, waiting for
  * the response to arrives before executing the next request.
diff --git a/api/src/main/java/org/asynchttpclient/generators/InputStreamBodyGenerator.java b/api/src/main/java/org/asynchttpclient/generators/InputStreamBodyGenerator.java
index 25080cfa31..34be273b95 100644
--- a/api/src/main/java/org/asynchttpclient/generators/InputStreamBodyGenerator.java
+++ b/api/src/main/java/org/asynchttpclient/generators/InputStreamBodyGenerator.java
@@ -13,15 +13,15 @@
 
 package org.asynchttpclient.generators;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
 import org.asynchttpclient.Body;
 import org.asynchttpclient.BodyGenerator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
 /**
  * A {@link BodyGenerator} which use an {@link InputStream} for reading bytes, without having to read the entire stream in memory.
  * 

diff --git a/api/src/main/java/org/asynchttpclient/listener/TransferCompletionHandler.java b/api/src/main/java/org/asynchttpclient/listener/TransferCompletionHandler.java index 94a5888af5..b39930dffd 100644 --- a/api/src/main/java/org/asynchttpclient/listener/TransferCompletionHandler.java +++ b/api/src/main/java/org/asynchttpclient/listener/TransferCompletionHandler.java @@ -12,8 +12,6 @@ */ package org.asynchttpclient.listener; -import java.util.concurrent.ConcurrentLinkedQueue; - import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseBodyPart; @@ -22,6 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.ConcurrentLinkedQueue; + /** * A {@link org.asynchttpclient.AsyncHandler} that can be used to notify a set of {@link TransferListener} *

diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index 1b293b178f..8057f9910e 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -15,11 +15,11 @@ */ package org.asynchttpclient.multipart; +import org.asynchttpclient.util.StandardCharsets; + import java.io.ByteArrayOutputStream; import java.io.IOException; -import org.asynchttpclient.util.StandardCharsets; - /** * This class is an adaptation of the Apache HttpClient implementation * diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index 96bb48aef1..b05802807d 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -15,6 +15,9 @@ */ package org.asynchttpclient.multipart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -24,9 +27,6 @@ import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class FilePart extends AbstractFilePart { private static final Logger LOGGER = LoggerFactory.getLogger(FilePart.class); diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java index 7e90917525..1515409364 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java @@ -12,6 +12,10 @@ */ package org.asynchttpclient.multipart; +import org.asynchttpclient.RandomAccessBody; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -20,10 +24,6 @@ import java.util.ArrayList; import java.util.List; -import org.asynchttpclient.RandomAccessBody; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class MultipartBody implements RandomAccessBody { private final static Logger LOGGER = LoggerFactory.getLogger(MultipartBody.class); diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index ac7b0b81e7..cfa188ff96 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java @@ -15,8 +15,14 @@ */ package org.asynchttpclient.multipart; -import static org.asynchttpclient.multipart.Part.*; -import static org.asynchttpclient.util.MiscUtil.*; +import static org.asynchttpclient.multipart.Part.CRLF_BYTES; +import static org.asynchttpclient.multipart.Part.EXTRA_BYTES; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.util.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -29,11 +35,6 @@ import java.util.Random; import java.util.Set; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.util.StandardCharsets; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class MultipartUtils { private static final Logger LOGGER = LoggerFactory.getLogger(MultipartUtils.class); diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index e2164f4e4a..849d721c1f 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -15,12 +15,12 @@ */ package org.asynchttpclient.multipart; +import org.asynchttpclient.util.StandardCharsets; + import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; -import org.asynchttpclient.util.StandardCharsets; - public abstract class Part { /** diff --git a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java b/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java index cb8f52964f..f3bcf9406d 100644 --- a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java +++ b/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java @@ -26,18 +26,18 @@ package org.asynchttpclient.ntlm; +import org.asynchttpclient.util.Base64; +import org.asynchttpclient.util.StandardCharsets; + +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 org.asynchttpclient.util.Base64; -import org.asynchttpclient.util.StandardCharsets; - /** * Provides an implementation for NTLMv1, NTLMv2, and NTLM2 Session forms of the NTLM * authentication protocol. diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java index da9c9454b5..82d9b5c45b 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java @@ -16,12 +16,6 @@ */ package org.asynchttpclient.oauth; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; - import org.asynchttpclient.FluentStringsMap; import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilderBase; @@ -30,6 +24,12 @@ import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.util.UTF8UrlEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Random; + /** * Simple OAuth signature calculator that can used for constructing client signatures * for accessing services that use OAuth for authorization. diff --git a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java b/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java index e06c39ff17..ba4cb6a089 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java +++ b/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java @@ -16,12 +16,12 @@ */ package org.asynchttpclient.oauth; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.util.UTF8UrlEncoder; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + /** * Since cloning (of MAC instances) is not necessarily supported on all platforms * (and specifically seems to fail on MacOS), let's wrap synchronization/reuse details here. diff --git a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java index 7d59c3ddd8..d2b4fc225f 100644 --- a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java +++ b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java @@ -2,10 +2,6 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import java.net.URI; -import java.util.Collections; -import java.util.List; - import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; @@ -14,6 +10,10 @@ import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.util.AsyncHttpProviderUtils; +import java.net.URI; +import java.util.Collections; +import java.util.List; + public abstract class ResponseBase implements Response { protected final static String DEFAULT_CHARSET = "ISO-8859-1"; diff --git a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java index f4610748e5..9f6959f608 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java +++ b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java @@ -20,7 +20,6 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.charset.Charset; import java.util.Map; import java.util.Scanner; import java.util.concurrent.ConcurrentHashMap; diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index fa5fa88b1f..cbc46cec57 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -12,6 +12,11 @@ */ package org.asynchttpclient.util; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.Request; + import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -19,11 +24,6 @@ import java.nio.charset.Charset; import java.util.List; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.AsyncHttpProvider; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.Request; - /** * {@link org.asynchttpclient.AsyncHttpProvider} common utilities. */ diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index b299378709..7b79ee9b2a 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -12,13 +12,13 @@ */ package org.asynchttpclient.util; -import static org.asynchttpclient.util.MiscUtil.*; - -import java.security.NoSuchAlgorithmException; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; +import java.security.NoSuchAlgorithmException; + public final class AuthenticatorUtils { public static String computeBasicAuthentication(Realm realm) { diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index 4ca53b809d..9e06f22858 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -14,14 +14,6 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -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.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.ProxyServer.Protocol; @@ -30,6 +22,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +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; + /** * Utilities for Proxy handling. * diff --git a/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index c90c526309..34a41e34e3 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -22,6 +22,7 @@ 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; diff --git a/api/src/test/java/org/asynchttpclient/RealmTest.java b/api/src/test/java/org/asynchttpclient/RealmTest.java index 49e151fb0b..11873f0126 100644 --- a/api/src/test/java/org/asynchttpclient/RealmTest.java +++ b/api/src/test/java/org/asynchttpclient/RealmTest.java @@ -14,14 +14,14 @@ import static org.testng.Assert.assertEquals; -import java.math.BigInteger; -import java.security.MessageDigest; - import org.asynchttpclient.Realm.AuthScheme; import org.asynchttpclient.Realm.RealmBuilder; import org.asynchttpclient.util.StandardCharsets; import org.testng.annotations.Test; +import java.math.BigInteger; +import java.security.MessageDigest; + public class RealmTest { @Test(groups = "fast") public void testClone() { diff --git a/api/src/test/java/org/asynchttpclient/async/AbstractBasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/AbstractBasicHttpsTest.java index 5af5d2f4b1..e95112a70c 100644 --- a/api/src/test/java/org/asynchttpclient/async/AbstractBasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AbstractBasicHttpsTest.java @@ -15,7 +15,8 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; import org.testng.annotations.BeforeClass; diff --git a/api/src/test/java/org/asynchttpclient/async/AbstractBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AbstractBasicTest.java index 1f7dba4e7b..224b24eb9a 100644 --- a/api/src/test/java/org/asynchttpclient/async/AbstractBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AbstractBasicTest.java @@ -15,7 +15,9 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.addHttpConnector; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; import static org.testng.Assert.fail; import org.asynchttpclient.AsyncCompletionHandler; diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 565ae6eb1b..ece7196939 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -15,9 +15,32 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.asynchttpclient.util.DateUtil.*; -import static org.testng.Assert.*; +import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.util.DateUtil.millisTime; +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.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpClientConfig.Builder; +import org.asynchttpclient.AsyncHttpClientConfigBean; +import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.MaxRedirectException; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Request; +import org.asynchttpclient.RequestBuilder; +import org.asynchttpclient.Response; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.multipart.StringPart; +import org.asynchttpclient.util.StandardCharsets; +import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -40,24 +63,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.asynchttpclient.AsyncCompletionHandler; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.AsyncHttpClientConfig.Builder; -import org.asynchttpclient.AsyncHttpClientConfigBean; -import org.asynchttpclient.AsyncHttpProviderConfig; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.MaxRedirectException; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.Request; -import org.asynchttpclient.RequestBuilder; -import org.asynchttpclient.Response; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.multipart.Part; -import org.asynchttpclient.multipart.StringPart; -import org.asynchttpclient.util.StandardCharsets; -import org.testng.annotations.Test; - public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider", "async" }) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 20c36c5745..610f521cae 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -16,7 +16,20 @@ package org.asynchttpclient.async; import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; -import static org.testng.Assert.*; +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.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.HttpResponseHeaders; +import org.asynchttpclient.HttpResponseStatus; +import org.asynchttpclient.Response; +import org.testng.annotations.Test; import java.util.Arrays; import java.util.Collection; @@ -29,16 +42,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; -import org.asynchttpclient.Response; -import org.testng.annotations.Test; - public abstract class AsyncStreamHandlerTest extends AbstractBasicTest { private static final String RESPONSE = "param_1_"; diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamLifecycleTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamLifecycleTest.java index 7288d31899..8e702da2d3 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamLifecycleTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamLifecycleTest.java @@ -15,21 +15,10 @@ */ package org.asynchttpclient.async; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; @@ -43,6 +32,20 @@ import org.testng.annotations.AfterClass; 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.io.PrintWriter; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + /** * Tests default asynchronous life cycle. * diff --git a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java index e7fed714a6..6edbf58fcb 100644 --- a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java @@ -12,17 +12,15 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.ADMIN; +import static org.asynchttpclient.async.util.TestUtils.USER; +import static org.asynchttpclient.async.util.TestUtils.addBasicAuthHandler; +import static org.asynchttpclient.async.util.TestUtils.addDigestAuthHandler; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -37,6 +35,15 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + public abstract class AuthTimeoutTest extends AbstractBasicTest { private Server server2; diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 15050e2905..541d7bd4b5 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -15,19 +15,16 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.ADMIN; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE_STRING; +import static org.asynchttpclient.async.util.TestUtils.USER; +import static org.asynchttpclient.async.util.TestUtils.addBasicAuthHandler; +import static org.asynchttpclient.async.util.TestUtils.addDigestAuthHandler; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; @@ -50,6 +47,17 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + public abstract class BasicAuthTest extends AbstractBasicTest { protected static final String MY_MESSAGE = "my message"; diff --git a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java index 1efde2f983..7bc7233783 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java @@ -15,22 +15,26 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.net.ConnectException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.SSLHandshakeException; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE_STRING; +import static org.asynchttpclient.async.util.TestUtils.createSSLContext; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig.Builder; import org.asynchttpclient.Response; import org.testng.annotations.Test; +import javax.net.ssl.SSLHandshakeException; +import javax.servlet.http.HttpServletResponse; + +import java.net.ConnectException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + public abstract class BasicHttpsTest extends AbstractBasicHttpsTest { protected String getTargetUrl() { diff --git a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java index e6d19b6401..917c8a58dd 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java @@ -15,6 +15,8 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.RequestBuilder; @@ -25,8 +27,6 @@ import java.io.ByteArrayInputStream; import java.util.concurrent.Future; -import static org.testng.Assert.assertEquals; - public abstract class BodyChunkTest extends AbstractBasicTest { private static final String MY_MESSAGE = "my message"; diff --git a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java index 09e16e9763..0f21806b9d 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java @@ -14,19 +14,11 @@ import static org.apache.commons.io.IOUtils.copy; import static org.asynchttpclient.async.util.TestUtils.findFreePort; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeoutException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -37,6 +29,18 @@ 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.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; + public abstract class BodyDeferringAsyncHandlerTest extends AbstractBasicTest { // not a half gig ;) for test shorter run's sake diff --git a/api/src/test/java/org/asynchttpclient/async/ByteBufferCapacityTest.java b/api/src/test/java/org/asynchttpclient/async/ByteBufferCapacityTest.java index d0ccfcee03..7223357bac 100644 --- a/api/src/test/java/org/asynchttpclient/async/ByteBufferCapacityTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ByteBufferCapacityTest.java @@ -13,18 +13,9 @@ package org.asynchttpclient.async; import static org.asynchttpclient.async.util.TestUtils.createTempFile; -import static org.testng.Assert.*; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.HttpResponseBodyPart; @@ -33,6 +24,17 @@ 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.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicInteger; + public abstract class ByteBufferCapacityTest extends AbstractBasicTest { private class BasicHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java index 66e9ef3692..013940ee3c 100644 --- a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java @@ -12,13 +12,12 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; +import static org.asynchttpclient.async.util.TestUtils.LARGE_IMAGE_BYTES; +import static org.asynchttpclient.async.util.TestUtils.LARGE_IMAGE_FILE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import static org.testng.FileAssert.fail; -import java.io.BufferedInputStream; -import java.io.FileInputStream; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Request; @@ -27,6 +26,9 @@ import org.asynchttpclient.generators.InputStreamBodyGenerator; import org.testng.annotations.Test; +import java.io.BufferedInputStream; +import java.io.FileInputStream; + /** * Test that the url fetcher is able to communicate via a proxy * diff --git a/api/src/test/java/org/asynchttpclient/async/ComplexClientTest.java b/api/src/test/java/org/asynchttpclient/async/ComplexClientTest.java index 39194b33d6..7ecc68efb6 100644 --- a/api/src/test/java/org/asynchttpclient/async/ComplexClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ComplexClientTest.java @@ -17,12 +17,12 @@ import static org.testng.Assert.assertEquals; -import java.util.concurrent.TimeUnit; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; import org.testng.annotations.Test; +import java.util.concurrent.TimeUnit; + public abstract class ComplexClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) diff --git a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java index ea29eb51a4..792d436d76 100644 --- a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java @@ -15,15 +15,10 @@ */ package org.asynchttpclient.async; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -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.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncCompletionHandlerBase; @@ -34,6 +29,14 @@ import org.slf4j.LoggerFactory; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + public abstract class ConnectionPoolTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); diff --git a/api/src/test/java/org/asynchttpclient/async/DigestAuthTest.java b/api/src/test/java/org/asynchttpclient/async/DigestAuthTest.java index 52c3789e89..2753c60625 100644 --- a/api/src/test/java/org/asynchttpclient/async/DigestAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/DigestAuthTest.java @@ -12,18 +12,13 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.ADMIN; +import static org.asynchttpclient.async.util.TestUtils.USER; +import static org.asynchttpclient.async.util.TestUtils.addDigestAuthHandler; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Realm; @@ -33,6 +28,16 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + public abstract class DigestAuthTest extends AbstractBasicTest { @BeforeClass(alwaysRun = true) diff --git a/api/src/test/java/org/asynchttpclient/async/EmptyBodyTest.java b/api/src/test/java/org/asynchttpclient/async/EmptyBodyTest.java index 9147a18eee..fc0693cba4 100644 --- a/api/src/test/java/org/asynchttpclient/async/EmptyBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/async/EmptyBodyTest.java @@ -15,6 +15,12 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.HttpResponseBodyPart; @@ -28,6 +34,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.io.InputStream; import java.util.concurrent.CountDownLatch; @@ -36,13 +43,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertNotNull; - -import static org.testng.Assert.fail; - /** * Tests case where response doesn't have body. * diff --git a/api/src/test/java/org/asynchttpclient/async/ErrorResponseTest.java b/api/src/test/java/org/asynchttpclient/async/ErrorResponseTest.java index 260d5f8fdc..4759564cf7 100644 --- a/api/src/test/java/org/asynchttpclient/async/ErrorResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ErrorResponseTest.java @@ -16,6 +16,9 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; import org.asynchttpclient.util.StandardCharsets; @@ -32,9 +35,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - /** * Tests to reproduce issues with handling of error responses * diff --git a/api/src/test/java/org/asynchttpclient/async/Expect100ContinueTest.java b/api/src/test/java/org/asynchttpclient/async/Expect100ContinueTest.java index a1de248e24..cb9694a819 100644 --- a/api/src/test/java/org/asynchttpclient/async/Expect100ContinueTest.java +++ b/api/src/test/java/org/asynchttpclient/async/Expect100ContinueTest.java @@ -15,15 +15,10 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.concurrent.Future; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE_STRING; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; @@ -31,6 +26,13 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.Future; + /** * Test the Expect: 100-Continue. */ diff --git a/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java index 1a981e5f71..18011253cc 100644 --- a/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java @@ -15,13 +15,6 @@ import static org.asynchttpclient.async.util.TestUtils.createTempFile; import static org.testng.Assert.assertEquals; -import java.io.File; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; import org.asynchttpclient.multipart.FilePart; @@ -30,6 +23,13 @@ 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.IOException; + public abstract class FastUnauthorizedUploadTest extends AbstractBasicTest { @Override diff --git a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java index c0e11610ce..470eeaaf8e 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java @@ -12,16 +12,9 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.File; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.LARGE_IMAGE_FILE; +import static org.asynchttpclient.async.util.TestUtils.createTempFile; +import static org.testng.Assert.assertEquals; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -32,6 +25,14 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; +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.IOException; + public abstract class FilePartLargeFileTest extends AbstractBasicTest { @Override diff --git a/api/src/test/java/org/asynchttpclient/async/FilterTest.java b/api/src/test/java/org/asynchttpclient/async/FilterTest.java index 8f4c90725e..58f4c44d93 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilterTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilterTest.java @@ -12,6 +12,10 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Request; @@ -27,6 +31,7 @@ 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; @@ -34,10 +39,6 @@ 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; - public abstract class FilterTest extends AbstractBasicTest { private static class BasicHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/FluentCaseInsensitiveStringsMapTest.java b/api/src/test/java/org/asynchttpclient/async/FluentCaseInsensitiveStringsMapTest.java index 97797d1396..51dee68600 100644 --- a/api/src/test/java/org/asynchttpclient/async/FluentCaseInsensitiveStringsMapTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FluentCaseInsensitiveStringsMapTest.java @@ -15,6 +15,10 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.testng.annotations.Test; @@ -25,10 +29,6 @@ import java.util.LinkedHashSet; import java.util.Map; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - public class FluentCaseInsensitiveStringsMapTest { @Test diff --git a/api/src/test/java/org/asynchttpclient/async/FluentStringsMapTest.java b/api/src/test/java/org/asynchttpclient/async/FluentStringsMapTest.java index 3a04b962d6..e9568773c6 100644 --- a/api/src/test/java/org/asynchttpclient/async/FluentStringsMapTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FluentStringsMapTest.java @@ -15,6 +15,10 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import org.asynchttpclient.FluentStringsMap; import org.testng.annotations.Test; @@ -25,10 +29,6 @@ import java.util.LinkedHashSet; import java.util.Map; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - public class FluentStringsMapTest { @Test diff --git a/api/src/test/java/org/asynchttpclient/async/Head302Test.java b/api/src/test/java/org/asynchttpclient/async/Head302Test.java index e19936ec4b..4ef5b2e3ec 100644 --- a/api/src/test/java/org/asynchttpclient/async/Head302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/Head302Test.java @@ -17,17 +17,6 @@ import static org.testng.Assert.fail; -import java.io.IOException; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Request; @@ -36,6 +25,17 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + /** * Tests HEAD request that gets 302 response. * diff --git a/api/src/test/java/org/asynchttpclient/async/HostnameVerifierTest.java b/api/src/test/java/org/asynchttpclient/async/HostnameVerifierTest.java index 82fc7cd3c0..083b2da0f6 100644 --- a/api/src/test/java/org/asynchttpclient/async/HostnameVerifierTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HostnameVerifierTest.java @@ -12,21 +12,13 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.net.ConnectException; -import java.util.Enumeration; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE_STRING; +import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; +import static org.asynchttpclient.async.util.TestUtils.createSSLContext; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig.Builder; @@ -37,6 +29,19 @@ import org.slf4j.LoggerFactory; import org.testng.annotations.Test; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.Enumeration; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; + public abstract class HostnameVerifierTest extends AbstractBasicHttpsTest { protected final Logger log = LoggerFactory.getLogger(HostnameVerifierTest.class); diff --git a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java index e9c6ae6c8d..40ebd79f87 100644 --- a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java @@ -15,16 +15,12 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; +import static org.asynchttpclient.async.util.TestUtils.addHttpsConnector; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -34,6 +30,14 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicBoolean; + public abstract class HttpToHttpsRedirectTest extends AbstractBasicTest { private final AtomicBoolean redirectDone = new AtomicBoolean(false); diff --git a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java index 3837b799c8..929ec24856 100644 --- a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java @@ -15,16 +15,10 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; import static org.testng.Assert.fail; -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.eclipse.jetty.server.Request; @@ -32,6 +26,13 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + public abstract class IdleStateHandlerTest extends AbstractBasicTest { private class IdleStateHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/InputStreamTest.java b/api/src/test/java/org/asynchttpclient/async/InputStreamTest.java index a519385473..bd5b47284f 100644 --- a/api/src/test/java/org/asynchttpclient/async/InputStreamTest.java +++ b/api/src/test/java/org/asynchttpclient/async/InputStreamTest.java @@ -15,6 +15,9 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.Response; @@ -25,15 +28,13 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.ByteArrayOutputStream; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - public abstract class InputStreamTest extends AbstractBasicTest { private static class InputStreamHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/ListenableFutureTest.java b/api/src/test/java/org/asynchttpclient/async/ListenableFutureTest.java index 3c026d8d57..3109ebf96f 100644 --- a/api/src/test/java/org/asynchttpclient/async/ListenableFutureTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ListenableFutureTest.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.ListenableFuture; import org.asynchttpclient.Response; @@ -23,8 +25,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.assertEquals; - public abstract class ListenableFutureTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) diff --git a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java index 48aaad6e24..1d6369762b 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java @@ -16,20 +16,9 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -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 javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -40,6 +29,18 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +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; + abstract public class MaxConnectionsInThreads extends AbstractBasicTest { // FIXME weird diff --git a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java index e2765f3a3e..d24c61f4a3 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java @@ -15,12 +15,15 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.testng.Assert.*; import org.testng.annotations.Test; import java.io.IOException; diff --git a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java index d1d36b3119..fc173e856b 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java @@ -12,28 +12,13 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; -import java.util.zip.GZIPInputStream; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.getClasspathFile; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +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; @@ -59,6 +44,26 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +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; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.zip.GZIPInputStream; + /** * @author dominict */ diff --git a/api/src/test/java/org/asynchttpclient/async/MultipleHeaderTest.java b/api/src/test/java/org/asynchttpclient/async/MultipleHeaderTest.java index f2855e8c7d..d7c1d99ac6 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipleHeaderTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipleHeaderTest.java @@ -13,7 +13,20 @@ package org.asynchttpclient.async; import static org.asynchttpclient.async.util.TestUtils.findFreePort; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.HttpResponseHeaders; +import org.asynchttpclient.HttpResponseStatus; +import org.asynchttpclient.Request; +import org.asynchttpclient.RequestBuilder; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; import java.io.BufferedReader; import java.io.IOException; @@ -31,17 +44,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; -import org.asynchttpclient.Request; -import org.asynchttpclient.RequestBuilder; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - /** * @author Hubert Iwaniuk */ diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 8d4359b4ea..363c7cbbec 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -16,16 +16,18 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; -import static org.testng.Assert.*; import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; + import java.security.GeneralSecurityException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; diff --git a/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java b/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java index f339a4a68c..937f607e3c 100644 --- a/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java @@ -12,28 +12,29 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; import static org.testng.Assert.assertEquals; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; -import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.Response; +import org.asynchttpclient.util.StandardCharsets; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +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 NonAsciiContentLengthTest extends AbstractBasicTest { @BeforeClass(alwaysRun = true) diff --git a/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java b/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java index 6fcf4f8c00..e7bd9dd9fa 100644 --- a/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java @@ -15,6 +15,10 @@ */ package org.asynchttpclient.async; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; @@ -24,16 +28,13 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - public abstract class ParamEncodingTest extends AbstractBasicTest { private class ParamEncoding extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java index edc1856ce5..746e2390bd 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java @@ -15,19 +15,12 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -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; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -37,6 +30,17 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.URI; +import java.util.Enumeration; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + public abstract class PerRequestRelative302Test extends AbstractBasicTest { private final AtomicBoolean isSet = new AtomicBoolean(false); diff --git a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java index d1a139f324..b0d2ef76bd 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java @@ -16,6 +16,12 @@ package org.asynchttpclient.async; import static org.asynchttpclient.util.DateUtil.millisTime; +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.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -30,18 +36,13 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -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; - /** * Per request timeout configuration test. * diff --git a/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java index af02a4ad17..3907683f9d 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java @@ -13,15 +13,8 @@ package org.asynchttpclient.async; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHttpClient; @@ -35,6 +28,14 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; + public abstract class PostRedirectGetTest extends AbstractBasicTest { // ------------------------------------------------------ Test Configuration diff --git a/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java b/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java index 49e4b2b6ea..d2356e782c 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java @@ -15,6 +15,10 @@ */ package org.asynchttpclient.async; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.HttpResponseStatus; @@ -28,16 +32,13 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - /** * Tests POST request with Query String. * diff --git a/api/src/test/java/org/asynchttpclient/async/ProxyTest.java b/api/src/test/java/org/asynchttpclient/async/ProxyTest.java index 5436cb05d8..3e5220d696 100644 --- a/api/src/test/java/org/asynchttpclient/async/ProxyTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ProxyTest.java @@ -15,7 +15,22 @@ */ package org.asynchttpclient.async; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Response; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.ConnectException; @@ -32,18 +47,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.Response; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.annotations.Test; - /** * Proxy usage tests. * diff --git a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java index 1fae3b193f..4f223f40ce 100644 --- a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java @@ -12,14 +12,11 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; import static org.testng.Assert.assertEquals; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeoutException; - import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -35,6 +32,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; + /** * Proxy usage tests. */ diff --git a/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java index e4f1a68c75..0d37f66e5c 100644 --- a/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java @@ -15,13 +15,6 @@ import static org.asynchttpclient.async.util.TestUtils.createTempFile; import static org.testng.Assert.assertEquals; -import java.io.File; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; @@ -29,6 +22,13 @@ 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.IOException; + /** * @author Benjamin Hanzelmann */ diff --git a/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java index 75468d28e7..7d267111ca 100644 --- a/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java +++ b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java @@ -15,6 +15,10 @@ */ package org.asynchttpclient.async; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; import org.asynchttpclient.util.StandardCharsets; @@ -35,10 +39,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - /** * Testing query parameters support. * diff --git a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java index 7cecf24d13..64c4e2e8ec 100644 --- a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java @@ -15,20 +15,10 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -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.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; @@ -43,6 +33,18 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + /** * Reverse C10K Problem test. * diff --git a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java index a27873d108..22bdb6b02d 100644 --- a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java @@ -15,17 +15,10 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -38,6 +31,15 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +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.util.Date; + /** * Test for multithreaded url fetcher calls that use two separate sets of ssl certificates. This then tests that the certificate settings do not clash (override each other), * resulting in the peer not authenticated exception diff --git a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java index 86c21eaac5..9eb0cadef0 100644 --- a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java @@ -15,19 +15,12 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -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; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -37,6 +30,17 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.URI; +import java.util.Enumeration; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + public abstract class Relative302Test extends AbstractBasicTest { private final AtomicBoolean isSet = new AtomicBoolean(false); diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index 93c3306306..2954a4bbd4 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -20,11 +20,6 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import org.apache.commons.io.IOUtils; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; @@ -39,6 +34,11 @@ import org.asynchttpclient.util.StandardCharsets; import org.testng.annotations.Test; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Unit tests for remote site. *

diff --git a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java index 586b74a50a..7d1408c1d0 100644 --- a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java @@ -15,6 +15,8 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; + import org.asynchttpclient.FluentStringsMap; import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilder; @@ -24,8 +26,6 @@ import java.io.UnsupportedEncodingException; import java.util.concurrent.ExecutionException; -import static org.testng.Assert.assertEquals; - public class RequestBuilderTest { private final static String SAFE_CHARS = diff --git a/api/src/test/java/org/asynchttpclient/async/RetryRequestTest.java b/api/src/test/java/org/asynchttpclient/async/RetryRequestTest.java index fdbc1af6dc..8706232a26 100644 --- a/api/src/test/java/org/asynchttpclient/async/RetryRequestTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RetryRequestTest.java @@ -12,6 +12,10 @@ */ package org.asynchttpclient.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.util.AsyncHttpProviderUtils; @@ -26,8 +30,6 @@ 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 { diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncClientErrorBehaviourTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncClientErrorBehaviourTest.java index b359058ac0..5912a7079a 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncClientErrorBehaviourTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncClientErrorBehaviourTest.java @@ -12,15 +12,8 @@ */ package org.asynchttpclient.async; -import static org.testng.Assert.*; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.concurrent.Future; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.Response; import org.asynchttpclient.SimpleAsyncHttpClient; @@ -29,6 +22,14 @@ 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.ByteArrayOutputStream; +import java.io.IOException; +import java.util.concurrent.Future; + /** * @author Benjamin Hanzelmann * diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index 475ca72f34..df07e31922 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -12,16 +12,11 @@ */ package org.asynchttpclient.async; -import static org.testng.Assert.*; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Future; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNotSame; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.asynchttpclient.Response; import org.asynchttpclient.SimpleAsyncHttpClient; @@ -35,6 +30,15 @@ import org.asynchttpclient.util.StandardCharsets; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { private final static String MY_MESSAGE = "my message"; diff --git a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java index 3bc7ec4918..3b1763e768 100644 --- a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java @@ -13,19 +13,10 @@ package org.asynchttpclient.async; import static org.asynchttpclient.async.util.TestUtils.createTempFile; -import static org.testng.Assert.*; - -import java.io.File; -import java.io.IOException; -import java.util.Enumeration; -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 javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +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.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -37,6 +28,18 @@ 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.IOException; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + public abstract class TransferListenerTest extends AbstractBasicTest { private class BasicHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/WebDavBasicTest.java b/api/src/test/java/org/asynchttpclient/async/WebDavBasicTest.java index ef16be723a..7045925d5e 100644 --- a/api/src/test/java/org/asynchttpclient/async/WebDavBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/WebDavBasicTest.java @@ -13,11 +13,9 @@ package org.asynchttpclient.async; import static org.asynchttpclient.async.util.TestUtils.findFreePort; -import static org.testng.Assert.*; - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.ExecutionException; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import org.apache.catalina.Context; import org.apache.catalina.Engine; @@ -37,6 +35,10 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + public abstract class WebDavBasicTest extends AbstractBasicTest { protected Embedded embedded; diff --git a/api/src/test/java/org/asynchttpclient/async/ZeroCopyFileTest.java b/api/src/test/java/org/asynchttpclient/async/ZeroCopyFileTest.java index 490931ce8c..0ef54128fc 100644 --- a/api/src/test/java/org/asynchttpclient/async/ZeroCopyFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ZeroCopyFileTest.java @@ -12,21 +12,12 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE; +import static org.asynchttpclient.async.util.TestUtils.SIMPLE_TEXT_FILE_STRING; +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 org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; @@ -39,6 +30,19 @@ 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.net.URISyntaxException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + /** * Zero copy test which use FileChannel.transfer under the hood . The same SSL test is also covered in {@link BasicHttpsTest} */ diff --git a/api/src/test/java/org/asynchttpclient/async/util/EchoHandler.java b/api/src/test/java/org/asynchttpclient/async/util/EchoHandler.java index 5d10eabe12..00e132c849 100644 --- a/api/src/test/java/org/asynchttpclient/async/util/EchoHandler.java +++ b/api/src/test/java/org/asynchttpclient/async/util/EchoHandler.java @@ -1,15 +1,15 @@ package org.asynchttpclient.async.util; -import java.io.IOException; -import java.util.Enumeration; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; +import java.io.IOException; +import java.util.Enumeration; public class EchoHandler extends AbstractHandler { diff --git a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java index 3db063613d..75aab93fe0 100644 --- a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java +++ b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java @@ -2,6 +2,32 @@ import static org.testng.Assert.assertEquals; +import org.apache.commons.io.FileUtils; +import org.asynchttpclient.async.HostnameVerifierTest; +import org.asynchttpclient.util.StandardCharsets; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.security.authentication.DigestAuthenticator; +import org.eclipse.jetty.security.authentication.LoginAuthenticator; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -23,32 +49,6 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.apache.commons.io.FileUtils; -import org.asynchttpclient.async.HostnameVerifierTest; -import org.asynchttpclient.util.StandardCharsets; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.security.authentication.DigestAuthenticator; -import org.eclipse.jetty.security.authentication.LoginAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.util.ssl.SslContextFactory; - public class TestUtils { public static final String USER = "user"; diff --git a/api/src/test/java/org/asynchttpclient/cookie/CookieDecoderTest.java b/api/src/test/java/org/asynchttpclient/cookie/CookieDecoderTest.java index 14b2cb2871..f14aaf0b78 100644 --- a/api/src/test/java/org/asynchttpclient/cookie/CookieDecoderTest.java +++ b/api/src/test/java/org/asynchttpclient/cookie/CookieDecoderTest.java @@ -15,8 +15,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.cookie.CookieDecoder; import org.testng.annotations.Test; public class CookieDecoderTest { diff --git a/api/src/test/java/org/asynchttpclient/generators/ByteArrayBodyGeneratorTest.java b/api/src/test/java/org/asynchttpclient/generators/ByteArrayBodyGeneratorTest.java index bec6bc7975..80645ba1eb 100644 --- a/api/src/test/java/org/asynchttpclient/generators/ByteArrayBodyGeneratorTest.java +++ b/api/src/test/java/org/asynchttpclient/generators/ByteArrayBodyGeneratorTest.java @@ -13,17 +13,15 @@ package org.asynchttpclient.generators; -import org.asynchttpclient.Body; +import static org.testng.Assert.assertEquals; -import org.asynchttpclient.generators.ByteArrayBodyGenerator; +import org.asynchttpclient.Body; import org.testng.annotations.Test; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Random; -import static org.testng.Assert.assertEquals; - /** * @author Bryan Davis bpd@keynetics.com */ diff --git a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java index d11f2a3973..9de0bfa50f 100644 --- a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java @@ -12,6 +12,12 @@ */ package org.asynchttpclient.multipart; +import org.asynchttpclient.Body; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.util.StandardCharsets; +import org.testng.Assert; +import org.testng.annotations.Test; + import java.io.File; import java.io.IOException; import java.net.URISyntaxException; @@ -20,12 +26,6 @@ import java.util.ArrayList; import java.util.List; -import org.asynchttpclient.Body; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.util.StandardCharsets; -import org.testng.Assert; -import org.testng.annotations.Test; - public class MultipartBodyTest { @Test(groups = "fast") diff --git a/api/src/test/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcesserTest.java b/api/src/test/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcesserTest.java index 39d4ce09c4..b5de1de8cf 100644 --- a/api/src/test/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcesserTest.java +++ b/api/src/test/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcesserTest.java @@ -13,13 +13,12 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -import org.asynchttpclient.resumable.PropertiesBasedResumableProcessor; +import static org.testng.Assert.assertEquals; + import org.testng.annotations.Test; import java.util.Map; -import static org.testng.Assert.assertEquals; - /** * @author Benjamin Hanzelmann */ diff --git a/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java index 7feb70ce74..5e3cc094aa 100644 --- a/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java @@ -13,14 +13,13 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilder; -import org.asynchttpclient.resumable.ResumableAsyncHandler; import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; - /** * @author Benjamin Hanzelmann */ diff --git a/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java b/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java index be33e4e90e..06ab8fbc12 100644 --- a/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java +++ b/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java @@ -14,10 +14,10 @@ import static org.testng.Assert.assertEquals; -import java.net.URI; - import org.testng.annotations.Test; +import java.net.URI; + public class AsyncHttpProviderUtilsTest { @Test(groups = "fast") diff --git a/api/src/test/java/org/asynchttpclient/util/ProxyUtilsTest.java b/api/src/test/java/org/asynchttpclient/util/ProxyUtilsTest.java index cd24e9ca08..fdcb8884bd 100644 --- a/api/src/test/java/org/asynchttpclient/util/ProxyUtilsTest.java +++ b/api/src/test/java/org/asynchttpclient/util/ProxyUtilsTest.java @@ -12,7 +12,8 @@ */ package org.asynchttpclient.util; -import static org.testng.Assert.*; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; diff --git a/api/src/test/java/org/asynchttpclient/websocket/AbstractBasicTest.java b/api/src/test/java/org/asynchttpclient/websocket/AbstractBasicTest.java index efabb307ad..f5f944d0c1 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/AbstractBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/AbstractBasicTest.java @@ -12,7 +12,8 @@ */ package org.asynchttpclient.websocket; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.testng.annotations.AfterClass; diff --git a/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java index 5a362fd53a..4272b3ac48 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java @@ -14,14 +14,14 @@ import static org.testng.Assert.assertEquals; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - import org.asynchttpclient.AsyncHttpClient; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; import org.testng.annotations.Test; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + public abstract class ByteMessageTest extends AbstractBasicTest { @Override diff --git a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java index e9cb9e40ec..a2b1519d9d 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java @@ -12,6 +12,10 @@ */ package org.asynchttpclient.websocket; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import org.asynchttpclient.AsyncHttpClient; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; @@ -20,10 +24,6 @@ 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 AbstractBasicTest { @Override diff --git a/api/src/test/java/org/asynchttpclient/websocket/EchoSocket.java b/api/src/test/java/org/asynchttpclient/websocket/EchoSocket.java index db4943dcba..9bc51fc790 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/EchoSocket.java +++ b/api/src/test/java/org/asynchttpclient/websocket/EchoSocket.java @@ -1,11 +1,11 @@ package org.asynchttpclient.websocket; -import java.io.IOException; -import java.nio.ByteBuffer; - import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.WebSocketAdapter; +import java.io.IOException; +import java.nio.ByteBuffer; + public class EchoSocket extends WebSocketAdapter { @Override diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index b9d8c89265..4df55e2537 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -17,9 +17,6 @@ import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; import static org.testng.Assert.assertEquals; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; @@ -31,6 +28,9 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + /** * Proxy usage tests. */ diff --git a/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java b/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java index 92e08e10a2..c0a6c2fc55 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java @@ -13,17 +13,11 @@ package org.asynchttpclient.websocket; -import static org.asynchttpclient.async.util.TestUtils.*; +import static org.asynchttpclient.async.util.TestUtils.addHttpConnector; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; import static org.testng.Assert.assertEquals; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.eclipse.jetty.server.Request; @@ -34,6 +28,14 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + public abstract class RedirectTest extends AbstractBasicTest { @BeforeClass diff --git a/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java index 8d9e28f593..2ec3c20e3d 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java @@ -12,16 +12,18 @@ */ package org.asynchttpclient.websocket; -import static org.testng.Assert.*; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; import org.testng.annotations.Test; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + public abstract class TextMessageTest extends AbstractBasicTest { @Override diff --git a/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java b/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java index 2576407a04..6ac40b92c6 100644 --- a/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java +++ b/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java @@ -12,13 +12,13 @@ */ package org.asynchttpclient.extra; +import org.asynchttpclient.ListenableFuture; + import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.asynchttpclient.ListenableFuture; - public final class ListenableFutureAdapter { /** diff --git a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java b/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java index c9b8759276..c3c24a4b31 100644 --- a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java +++ b/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java @@ -1,8 +1,5 @@ package org.asynchttpclient.extra; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.RequestFilter; @@ -11,6 +8,9 @@ import com.google.common.util.concurrent.RateLimiter; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + /** * A {@link org.asynchttpclient.filter.RequestFilter} that extends the capability of * {@link ThrottleRequestFilter} by allowing rate limiting per second in addition to the diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java index 570cc739d7..d0b928cb1d 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java @@ -15,16 +15,15 @@ */ package org.asynchttpclient.extra; -import java.io.IOException; - +import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; -import org.jdeferred.Promise; -import org.jdeferred.impl.DeferredObject; - import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; -import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.Response; +import org.jdeferred.Promise; +import org.jdeferred.impl.DeferredObject; + +import java.io.IOException; public class AsyncHttpDeferredObject extends DeferredObject { public AsyncHttpDeferredObject(BoundRequestBuilder builder) throws IOException { diff --git a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java index 3ee7428450..de50435835 100644 --- a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java +++ b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java @@ -15,11 +15,8 @@ */ package org.asynchttpclient.extra; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; @@ -29,6 +26,10 @@ import org.jdeferred.impl.DefaultDeferredManager; import org.jdeferred.multiple.MultipleResults; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + public class AsyncHttpTest { protected DefaultDeferredManager deferredManager = new DefaultDeferredManager(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index 8b2ebd4fb3..7cc219545b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -13,6 +13,8 @@ package org.asynchttpclient.providers.grizzly; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.ConnectionPoolKeyStrategy; @@ -47,8 +49,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import static java.util.concurrent.TimeUnit.MILLISECONDS; - public class ConnectionManager { private static final Attribute DO_NOT_CACHE = diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index c79ab3e2c6..334dcac2ab 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -13,6 +13,10 @@ package org.asynchttpclient.providers.grizzly; +import static org.asynchttpclient.AsyncHandler.STATE.ABORT; +import static org.asynchttpclient.AsyncHandler.STATE.UPGRADE; +import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.CONTINUE; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProviderConfig; @@ -52,10 +56,6 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.asynchttpclient.AsyncHandler.STATE.ABORT; -import static org.asynchttpclient.AsyncHandler.STATE.UPGRADE; -import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.CONTINUE; - public final class EventHandler { private static final Map HANDLER_MAP = diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java index 58dbc72099..fd5965e812 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java @@ -12,9 +12,9 @@ */ package org.asynchttpclient.providers.grizzly; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.ExecutionException; +import static java.lang.Boolean.TRUE; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.glassfish.grizzly.utils.Exceptions.makeIOException; import org.asynchttpclient.Body; import org.asynchttpclient.BodyGenerator; @@ -29,14 +29,12 @@ import org.glassfish.grizzly.http.HttpContext; 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.threadpool.Threads; import org.glassfish.grizzly.utils.Futures; -import static java.lang.Boolean.TRUE; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.glassfish.grizzly.utils.Exceptions.*; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.ExecutionException; /** * {@link BodyGenerator} which may return just part of the payload at the time diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index efad63b22a..0225f79f50 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -13,6 +13,10 @@ package org.asynchttpclient.providers.grizzly; +import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.CONNECTION_POOL; +import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE; +import static org.glassfish.grizzly.asyncqueue.AsyncQueueWriter.AUTO_SIZE; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; @@ -20,6 +24,7 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; import org.asynchttpclient.ntlm.NTLMEngine; +import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property; import org.asynchttpclient.providers.grizzly.filters.AsyncHttpClientEventFilter; import org.asynchttpclient.providers.grizzly.filters.AsyncHttpClientFilter; import org.asynchttpclient.providers.grizzly.filters.AsyncSpdyClientEventFilter; @@ -28,7 +33,6 @@ import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.util.ProxyUtils; import org.asynchttpclient.util.SslUtils; - import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.WriteResult; @@ -40,6 +44,9 @@ import org.glassfish.grizzly.http.ContentEncoding; import org.glassfish.grizzly.http.GZipContentEncoding; import org.glassfish.grizzly.http.HttpClientFilter; +import org.glassfish.grizzly.impl.SafeFutureImpl; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; import org.glassfish.grizzly.npn.ClientSideNegotiator; import org.glassfish.grizzly.spdy.NextProtoNegSupport; import org.glassfish.grizzly.spdy.SpdyFramingFilter; @@ -48,12 +55,9 @@ import org.glassfish.grizzly.spdy.SpdySession; import org.glassfish.grizzly.ssl.SSLBaseFilter; import org.glassfish.grizzly.ssl.SSLConnectionContext; -import org.glassfish.grizzly.ssl.SSLUtils; -import org.glassfish.grizzly.impl.SafeFutureImpl; -import org.glassfish.grizzly.nio.transport.TCPNIOTransport; -import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.grizzly.ssl.SSLFilter; +import org.glassfish.grizzly.ssl.SSLUtils; import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy; import org.glassfish.grizzly.utils.DelayedExecutor; import org.glassfish.grizzly.utils.IdleTimeoutFilter; @@ -63,17 +67,13 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; + import java.io.IOException; import java.util.LinkedHashSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property; -import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.CONNECTION_POOL; -import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE; -import static org.glassfish.grizzly.asyncqueue.AsyncQueueWriter.AUTO_SIZE; - /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. * diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java index f456bc0890..058ae4ed4f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java @@ -14,7 +14,6 @@ package org.asynchttpclient.providers.grizzly; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import static org.glassfish.grizzly.http.CookiesBuilder.ServerCookiesBuilder; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; @@ -24,11 +23,12 @@ import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.http.Cookies; +import org.glassfish.grizzly.http.CookiesBuilder.ServerCookiesBuilder; import org.glassfish.grizzly.http.util.Header; -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 org.glassfish.grizzly.utils.Charsets; import java.io.IOException; import java.io.InputStream; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java index f5443ab868..82469fa80c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java @@ -14,7 +14,6 @@ package org.asynchttpclient.providers.grizzly; import org.asynchttpclient.HttpResponseBodyPart; - import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.http.HttpContent; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java index 51fcd5c663..d834ab6653 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java @@ -17,7 +17,6 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; import org.asynchttpclient.listenable.AbstractListenableFuture; - import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.impl.FutureImpl; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java index babd1af641..b5aa6438b9 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java @@ -15,7 +15,6 @@ import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseHeaders; - import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.util.MimeHeaders; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java index df80f4e978..f7d03dbf3b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java @@ -13,9 +13,6 @@ package org.asynchttpclient.providers.grizzly; -import java.net.URI; -import java.util.List; - import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; @@ -23,6 +20,9 @@ import org.asynchttpclient.Response; import org.glassfish.grizzly.http.HttpResponsePacket; +import java.net.URI; +import java.util.List; + /** * {@link HttpResponseStatus} implementation using the Grizzly 2.0 HTTP client * codec. diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index ce4368dd97..766c233c6e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java @@ -17,6 +17,7 @@ import org.asynchttpclient.Request; import org.asynchttpclient.providers.grizzly.bodyhandler.BodyHandler; import org.asynchttpclient.providers.grizzly.statushandler.StatusHandler; +import org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.websocket.WebSocket; import org.glassfish.grizzly.CloseListener; @@ -33,8 +34,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus; - public final class HttpTxContext { private static final Attribute REQUEST_STATE_ATTR = diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java index c995adef2c..603587fbe0 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java @@ -21,7 +21,6 @@ import org.glassfish.grizzly.http.HttpRequestPacket; import org.glassfish.grizzly.memory.Buffers; import org.glassfish.grizzly.memory.MemoryManager; -import org.glassfish.grizzly.utils.Charsets; import java.io.IOException; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java index cf4f9f4307..374454e9d4 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java @@ -13,6 +13,8 @@ package org.asynchttpclient.providers.grizzly.bodyhandler; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.FluentStringsMap; import org.asynchttpclient.Request; import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; @@ -29,8 +31,6 @@ import java.util.List; import java.util.Map; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; - public final class ParamsBodyHandler implements BodyHandler { private final boolean compressionEnabled; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java index a9a8819264..90cfb80849 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java @@ -13,10 +13,7 @@ package org.asynchttpclient.providers.grizzly.bodyhandler; -import static org.asynchttpclient.util.MiscUtil.*; - -import java.io.IOException; -import java.util.List; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; import org.asynchttpclient.Body; import org.asynchttpclient.Request; @@ -31,6 +28,9 @@ import org.glassfish.grizzly.memory.Buffers; import org.glassfish.grizzly.memory.MemoryManager; +import java.io.IOException; +import java.util.List; + public final class PartsBodyHandler implements BodyHandler { // -------------------------------------------- Methods from BodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java index a9b5948ea8..320d846b9a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java @@ -13,6 +13,8 @@ package org.asynchttpclient.providers.grizzly.bodyhandler; +import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.LOGGER; + import org.asynchttpclient.Request; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.filterchain.FilterChainContext; @@ -23,8 +25,6 @@ import java.io.IOException; import java.io.InputStream; -import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.LOGGER; - public final class StreamDataBodyHandler implements BodyHandler { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index ced4d0fe82..2925b96b07 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -13,6 +13,10 @@ package org.asynchttpclient.providers.grizzly.filters; +import static org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter.getHandshakeError; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -38,6 +42,7 @@ import org.asynchttpclient.providers.grizzly.filters.events.TunnelRequestEvent; import org.asynchttpclient.util.StandardCharsets; import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.filterchain.BaseFilter; @@ -45,8 +50,10 @@ import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.filterchain.FilterChainEvent; import org.glassfish.grizzly.filterchain.NextAction; +import org.glassfish.grizzly.http.HttpContent; import org.glassfish.grizzly.http.HttpContext; import org.glassfish.grizzly.http.HttpRequestPacket; +import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.Method; import org.glassfish.grizzly.http.ProcessingState; import org.glassfish.grizzly.http.Protocol; @@ -59,6 +66,7 @@ import org.glassfish.grizzly.ssl.SSLConnectionContext; import org.glassfish.grizzly.ssl.SSLUtils; import org.glassfish.grizzly.websockets.Version; +import org.slf4j.Logger; import java.io.File; import java.io.IOException; @@ -72,15 +80,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.Lock; -import org.glassfish.grizzly.Connection; -import org.glassfish.grizzly.http.HttpContent; -import org.glassfish.grizzly.http.HttpResponsePacket; -import org.slf4j.Logger; - -import static org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter.getHandshakeError; -import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; - /** * This {@link org.glassfish.grizzly.filterchain.Filter} is typically the last in the {@FilterChain}. Its primary responsibility is converting the async-http-client * {@link Request} into a Grizzly {@link HttpRequestPacket}. diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index 243670349d..899e3af10d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -13,6 +13,10 @@ package org.asynchttpclient.providers.grizzly.filters; +import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.NTLM_ENGINE; +import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; +import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; @@ -26,10 +30,6 @@ import java.io.IOException; -import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.NTLM_ENGINE; -import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; -import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; - /** * This Filter will be placed in the FilterChain when a request is being * proxied. It's main responsibility is to adjust the incoming request diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index 3a6d36e773..4ec3f6a25b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java @@ -28,6 +28,7 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLHandshakeException; + import java.io.IOException; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java index 6093116ecc..5f99182e7f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java @@ -13,6 +13,8 @@ package org.asynchttpclient.providers.grizzly.statushandler; +import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.STOP; + import org.asynchttpclient.Realm; import org.asynchttpclient.Request; import org.asynchttpclient.providers.grizzly.ConnectionManager; @@ -27,8 +29,6 @@ import java.security.NoSuchAlgorithmException; import java.util.Locale; -import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.STOP; - public final class AuthorizationHandler implements StatusHandler { public static final AuthorizationHandler INSTANCE = diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java index 4a17602a3f..1d9f566363 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java @@ -13,6 +13,8 @@ package org.asynchttpclient.providers.grizzly.statushandler; +import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.CONTINUE; + import org.asynchttpclient.Request; import org.asynchttpclient.providers.grizzly.ConnectionManager; import org.asynchttpclient.providers.grizzly.EventHandler; @@ -25,8 +27,6 @@ import java.net.URI; -import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.CONTINUE; - public final class RedirectHandler implements StatusHandler { public static final RedirectHandler INSTANCE = new RedirectHandler(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java index aea9a4ee98..03cc157e4a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java @@ -13,12 +13,12 @@ package org.asynchttpclient.providers.grizzly.websocket; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.websocket.WebSocket; import org.asynchttpclient.websocket.WebSocketListener; import org.glassfish.grizzly.websockets.SimpleWebSocket; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; - public final class GrizzlyWebSocketAdapter implements WebSocket { private final SimpleWebSocket gWebSocket; diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java index b558e8cf61..d0e761d800 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java @@ -16,7 +16,6 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.async.BasicAuthTest; -import org.testng.annotations.Test; public class GrizzlyBasicAuthTest extends BasicAuthTest { diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java index 44ba8533c1..a1c365f437 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java @@ -13,6 +13,10 @@ package org.asynchttpclient.providers.grizzly; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; @@ -21,8 +25,6 @@ import java.util.concurrent.TimeUnit; -import static org.testng.Assert.*; - public class GrizzlyConnectionPoolTest extends ConnectionPoolTest { @Override diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java index 67021c9232..83368e7892 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java @@ -17,7 +17,6 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyProviderUtil { diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java index e5dcdd07ab..c6b05085ef 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -13,17 +13,10 @@ package org.asynchttpclient.providers.grizzly; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHttpClient; @@ -36,6 +29,16 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + public class GrizzlyUnexpectingTimeoutTest extends AbstractBasicTest { private static final String MSG = "Unauthorized without WWW-Authenticate header"; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java index ae09325763..17091a3d49 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -15,9 +15,6 @@ */ package org.asynchttpclient.providers.netty; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; @@ -28,6 +25,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + public class NettyAsyncHttpProvider implements AsyncHttpProvider { private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index f497d9ae1c..c1b554babc 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -16,6 +16,14 @@ */ package org.asynchttpclient.providers.netty; +import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelPool; +import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; +import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; @@ -26,14 +34,6 @@ import java.util.Map; import java.util.Set; -import org.asynchttpclient.AsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.ChannelPool; -import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; -import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 087b79787c..55b20abc16 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -18,6 +18,22 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; + +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.ConnectionPoolKeyStrategy; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.providers.netty.Callback; +import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.handler.Processor; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; +import org.asynchttpclient.util.SslUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; @@ -39,6 +55,8 @@ import io.netty.util.Timeout; import io.netty.util.TimerTask; +import javax.net.ssl.SSLEngine; + import java.io.IOException; import java.lang.reflect.Field; import java.net.URI; @@ -50,23 +68,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import javax.net.ssl.SSLEngine; - -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.providers.netty.Callback; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.handler.Processor; -import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; -import org.asynchttpclient.util.SslUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class Channels { private static final Logger LOGGER = LoggerFactory.getLogger(Channels.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 3d7292ec0c..9a9cf76602 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -13,6 +13,13 @@ package org.asynchttpclient.providers.netty.channel; import static org.asynchttpclient.util.DateUtil.millisTime; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; @@ -26,12 +33,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * A simple implementation of {@link ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index c48b419460..11550f74f7 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -16,6 +16,20 @@ package org.asynchttpclient.providers.netty.future; import static org.asynchttpclient.util.DateUtil.millisTime; + +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.ConnectionPoolKeyStrategy; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Request; +import org.asynchttpclient.listenable.AbstractListenableFuture; +import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.request.NettyRequest; +import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; @@ -32,19 +46,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.Request; -import org.asynchttpclient.listenable.AbstractListenableFuture; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.request.NettyRequest; -import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. * diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 20d93aed94..033e3c0b5b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -21,19 +21,6 @@ import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpContent; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.util.List; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandler.STATE; @@ -61,6 +48,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.util.List; + final class HttpProtocol extends Protocol { private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 31805011ce..28f17bb924 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -15,17 +15,6 @@ */ package org.asynchttpclient.providers.netty.handler; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.PrematureChannelClosureException; -import io.netty.handler.codec.http.LastHttpContent; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.util.concurrent.atomic.AtomicBoolean; - import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.DiscardEvent; @@ -38,6 +27,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.PrematureChannelClosureException; +import io.netty.handler.codec.http.LastHttpContent; + +import java.io.IOException; +import java.nio.channels.ClosedChannelException; +import java.util.concurrent.atomic.AtomicBoolean; + @Sharable public class Processor extends ChannelInboundHandlerAdapter { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 5097b555df..9d3e358a68 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -18,13 +18,6 @@ import static io.netty.handler.codec.http.HttpResponseStatus.TEMPORARY_REDIRECT; import static org.asynchttpclient.providers.netty.util.HttpUtil.HTTP; import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpResponse; - -import java.io.IOException; -import java.net.URI; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -48,6 +41,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponse; + +import java.io.IOException; +import java.net.URI; + public abstract class Protocol { private final Logger logger = LoggerFactory.getLogger(getClass()); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 7ffd961f42..48ff1cdbdd 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -16,17 +16,6 @@ package org.asynchttpclient.providers.netty.handler; import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; - -import java.io.IOException; -import java.util.Locale; import org.asynchttpclient.AsyncHandler.STATE; import org.asynchttpclient.AsyncHttpClientConfig; @@ -48,6 +37,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; + +import java.io.IOException; +import java.util.Locale; + final class WebSocketProtocol extends Protocol { private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 3867d1a074..941ade5afe 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -16,6 +16,13 @@ */ package org.asynchttpclient.providers.netty.request; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.future.StackTraceInspector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; @@ -24,13 +31,6 @@ import java.net.ConnectException; import java.nio.channels.ClosedChannelException; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.future.StackTraceInspector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Non Blocking connect. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index fbd1e10bbd..027ec95716 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -20,20 +20,6 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import io.netty.buffer.Unpooled; -import io.netty.handler.codec.http.DefaultFullHttpRequest; -import io.netty.handler.codec.http.DefaultHttpRequest; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpVersion; - -import java.io.IOException; -import java.net.URI; -import java.nio.charset.Charset; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Map.Entry; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.FluentStringsMap; @@ -59,6 +45,21 @@ import org.asynchttpclient.util.AuthenticatorUtils; import org.asynchttpclient.util.UTF8UrlEncoder; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; + +import java.io.IOException; +import java.net.URI; +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; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 39a14726c8..026e362f7c 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -17,20 +17,6 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.util.Timeout; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.URI; -import java.util.Map; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandlerExtensions; @@ -56,6 +42,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.util.Timeout; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + public class NettyRequestSender { private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java index a869bac5f2..2f11214899 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java @@ -15,12 +15,6 @@ */ package org.asynchttpclient.providers.netty.request; -import io.netty.channel.Channel; -import io.netty.channel.ChannelProgressiveFuture; -import io.netty.channel.ChannelProgressiveFutureListener; - -import java.nio.channels.ClosedChannelException; - import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProgressAsyncHandler; @@ -30,6 +24,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.channel.Channel; +import io.netty.channel.ChannelProgressiveFuture; +import io.netty.channel.ChannelProgressiveFutureListener; + +import java.nio.channels.ClosedChannelException; + public class ProgressListener implements ChannelProgressiveFutureListener { private static final Logger LOGGER = LoggerFactory.getLogger(ProgressListener.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 7dfb7afdb9..7d005c6c0d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -12,14 +12,14 @@ */ package org.asynchttpclient.providers.netty.request.body; +import org.asynchttpclient.RandomAccessBody; + import io.netty.channel.FileRegion; import io.netty.util.AbstractReferenceCounted; import java.io.IOException; import java.nio.channels.WritableByteChannel; -import org.asynchttpclient.RandomAccessBody; - /** * Adapts a {@link RandomAccessBody} to Netty's {@link FileRegion}. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java index c15c950bc0..26667946b9 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java @@ -12,16 +12,16 @@ */ package org.asynchttpclient.providers.netty.request.body; +import org.asynchttpclient.Body; +import org.asynchttpclient.BodyGenerator; +import org.asynchttpclient.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; -import org.asynchttpclient.Body; -import org.asynchttpclient.BodyGenerator; -import org.asynchttpclient.util.StandardCharsets; - /** * {@link BodyGenerator} which may return just part of the payload at the time * handler is requesting it. If it happens - PartialBodyGenerator becomes responsible diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java index 63a1fe0bd0..c35606d17b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java @@ -15,12 +15,12 @@ */ package org.asynchttpclient.providers.netty.request.body; -import java.io.IOException; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import io.netty.channel.Channel; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import java.io.IOException; public interface NettyBody { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index d16df6bfc6..fb9108e7b1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -15,14 +15,6 @@ */ package org.asynchttpclient.providers.netty.request.body; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelProgressiveFuture; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.stream.ChunkedWriteHandler; - -import java.io.IOException; - import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Body; import org.asynchttpclient.BodyGenerator; @@ -35,6 +27,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelProgressiveFuture; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.stream.ChunkedWriteHandler; + +import java.io.IOException; + public class NettyBodyBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java index 393349b089..eb2e9e9bfb 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient.providers.netty.request.body; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; + import io.netty.channel.Channel; import java.io.IOException; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; - public class NettyByteArrayBody implements NettyBody { private final byte[] bytes; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java index 24865b71c6..5360943b26 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -15,6 +15,14 @@ */ package org.asynchttpclient.providers.netty.request.body; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.ProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelProgressiveFuture; @@ -27,14 +35,6 @@ import java.io.IOException; import java.io.RandomAccessFile; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class NettyFileBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java index 0247cccc5f..318c9a4a96 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java @@ -15,6 +15,12 @@ */ package org.asynchttpclient.providers.netty.request.body; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.ProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.channel.ChannelProgressiveFuture; import io.netty.handler.codec.http.LastHttpContent; @@ -23,12 +29,6 @@ import java.io.IOException; import java.io.InputStream; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class NettyInputStreamBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyInputStreamBody.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java index 6124adead4..3b5fe4ca13 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java @@ -15,14 +15,14 @@ */ package org.asynchttpclient.providers.netty.request.body; -import java.util.List; - import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.multipart.MultipartBody; import org.asynchttpclient.multipart.MultipartUtils; import org.asynchttpclient.multipart.Part; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import java.util.List; + public class NettyMultipartBody extends NettyBodyBody { private final String contentType; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java index 13cec3543f..24ce37a33a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java @@ -16,13 +16,14 @@ package org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtil.millisTime; -import io.netty.util.Timeout; - -import java.util.concurrent.atomic.AtomicBoolean; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import io.netty.util.Timeout; + +import java.util.concurrent.atomic.AtomicBoolean; + public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { private final long idleConnectionTimeout; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 3e72c879bb..9fdcd8bc46 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -16,13 +16,14 @@ package org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtil.millisTime; -import io.netty.util.Timeout; - -import java.util.concurrent.atomic.AtomicBoolean; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import io.netty.util.Timeout; + +import java.util.concurrent.atomic.AtomicBoolean; + public class RequestTimeoutTimerTask extends TimeoutTimerTask { public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, Channels channels, TimeoutsHolder timeoutsHolder, AtomicBoolean clientClosed) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java index 3e81660305..715e1c773e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java @@ -15,16 +15,16 @@ */ package org.asynchttpclient.providers.netty.request.timeout; -import io.netty.util.TimerTask; - -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.util.TimerTask; + +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); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java index 23afb13c77..32ee9e6e22 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java @@ -15,6 +15,8 @@ */ package org.asynchttpclient.providers.netty.response; +import org.asynchttpclient.providers.netty.util.ByteBufUtil; + import io.netty.buffer.ByteBuf; import java.io.ByteArrayInputStream; @@ -23,8 +25,6 @@ import java.io.OutputStream; import java.nio.ByteBuffer; -import org.asynchttpclient.providers.netty.util.ByteBufUtil; - /** * A callback class used when an HTTP response body is received. * Bytes are eagerly fetched from the ByteBuf diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java index e58dedd451..7c57005112 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java @@ -15,16 +15,6 @@ */ package org.asynchttpclient.providers.netty.response; -import io.netty.handler.codec.http.HttpHeaders; - -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 org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; @@ -35,6 +25,16 @@ import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.util.MiscUtil; +import io.netty.handler.codec.http.HttpHeaders; + +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; + /** * Wrapper around the {@link org.asynchttpclient.Response} API. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java index c48aad3394..7268e2dbd4 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java @@ -15,14 +15,14 @@ */ package org.asynchttpclient.providers.netty.response; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.HttpResponseHeaders; + import io.netty.handler.codec.http.HttpHeaders; import java.net.URI; import java.util.Map; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.HttpResponseHeaders; - /** * A class that represent the HTTP headers. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java index 468bbf7204..29e23e84e6 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java @@ -16,17 +16,17 @@ */ package org.asynchttpclient.providers.netty.response; -import io.netty.handler.codec.http.HttpResponse; - -import java.net.URI; -import java.util.List; - import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Response; +import io.netty.handler.codec.http.HttpResponse; + +import java.net.URI; +import java.util.List; + /** * A class that represent the HTTP response' status line (code + text) */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 846a4d0bcd..e9c32e6f28 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -12,25 +12,26 @@ */ package org.asynchttpclient.providers.netty.ws; +import static io.netty.buffer.Unpooled.wrappedBuffer; + import org.asynchttpclient.websocket.WebSocket; import org.asynchttpclient.websocket.WebSocketByteListener; import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; import org.asynchttpclient.websocket.WebSocketListener; import org.asynchttpclient.websocket.WebSocketTextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.netty.channel.Channel; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; import java.util.concurrent.ConcurrentLinkedQueue; -import static io.netty.buffer.Unpooled.wrappedBuffer; - public class NettyWebSocket implements WebSocket { private final static Logger logger = LoggerFactory.getLogger(NettyWebSocket.class); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java index bb82b6cf76..40134e7924 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java @@ -12,13 +12,13 @@ */ package org.asynchttpclient.providers.netty.ws; +import org.asynchttpclient.util.Base64; +import org.asynchttpclient.util.StandardCharsets; + import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import org.asynchttpclient.util.Base64; -import org.asynchttpclient.util.StandardCharsets; - public final class WebSocketUtil { public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java index ab0a698ad6..37d0d63e0a 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java @@ -13,14 +13,8 @@ package org.asynchttpclient.providers.netty; -import static org.testng.Assert.*; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.http.HttpMessage; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -31,6 +25,14 @@ import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig.AdditionalChannelInitializer; import org.testng.annotations.Test; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http.HttpMessage; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class NettyAsyncProviderPipelineTest extends AbstractBasicTest { @Override diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java index 6d2b7b8002..f35b77dafb 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java @@ -13,13 +13,7 @@ package org.asynchttpclient.providers.netty; -import static org.testng.Assert.*; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; +import static org.testng.Assert.assertEquals; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseHeaders; @@ -28,6 +22,12 @@ import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.testng.annotations.Test; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + /** * @author Benjamin Hanzelmann */ diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java index e675f9713f..198f954bce 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java @@ -14,10 +14,6 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import io.netty.channel.Channel; - -import java.net.ConnectException; -import java.util.concurrent.TimeUnit; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -26,6 +22,11 @@ import org.asynchttpclient.providers.netty.channel.ChannelPool; import org.testng.annotations.Test; +import io.netty.channel.Channel; + +import java.net.ConnectException; +import java.util.concurrent.TimeUnit; + public class NettyConnectionPoolTest extends ConnectionPoolTest { @Override diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java index c9b4707df2..706baa3730 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.providers.netty; -import static org.testng.Assert.*; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java index 0d44378473..8618a4a6ce 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java @@ -12,20 +12,8 @@ */ package org.asynchttpclient.providers.netty; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHttpClient; @@ -38,6 +26,19 @@ 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.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + public class NettyRequestThrottleTimeoutTest extends AbstractBasicTest { private static final String MSG = "Enough is enough."; private static final int SLEEPTIME_MS = 1000; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java index dd946b7bf1..ab4fda18b4 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java @@ -12,21 +12,10 @@ */ package org.asynchttpclient.providers.netty; -import static org.asynchttpclient.async.util.TestUtils.*; -import static org.testng.Assert.*; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import static org.asynchttpclient.async.util.TestUtils.findFreePort; +import static org.asynchttpclient.async.util.TestUtils.newJettyHttpServer; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -40,6 +29,19 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +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.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; + //FIXME there's no retry actually public class RetryNonBlockingIssue extends AbstractBasicTest { From 272144efa416567553306525e14e5eb7c889fe45 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:54:34 +0100 Subject: [PATCH 0011/2070] Missing headers --- .../asynchttpclient/providers/netty/Callback.java | 14 +++++++++++++- .../providers/netty/DiscardEvent.java | 14 +++++++++++++- .../netty/future/StackTraceInspector.java | 12 ++++++++++++ .../netty/request/body/NettyMultipartBody.java | 2 +- .../providers/netty/util/CleanupChannelGroup.java | 1 - .../providers/netty/util/HttpUtil.java | 12 ++++++++++++ 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/Callback.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/Callback.java index 277b424e13..14328ca42e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/Callback.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/Callback.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.providers.netty; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; @@ -15,4 +27,4 @@ public Callback(NettyResponseFuture future) { public NettyResponseFuture future() { return future; } -} \ No newline at end of file +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java index f18c40f962..9765c34305 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java @@ -1,6 +1,18 @@ +/* + * 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 org.asynchttpclient.providers.netty; // Simple marker for stopping publishing bytes. public enum DiscardEvent { INSTANCE; -} \ No newline at end of file +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index 4541e0c219..94abc067b2 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.providers.netty.future; public class StackTraceInspector { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java index 3b5fe4ca13..742ed21657 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java @@ -39,5 +39,5 @@ private NettyMultipartBody(MultipartBody body, NettyAsyncHttpProviderConfig nett @Override public String getContentType() { return contentType; - }; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java index 671da09988..666a19d7ab 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java @@ -25,7 +25,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.asynchttpclient.providers.netty.util; import io.netty.channel.Channel; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java index b01a290740..66d3854858 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.providers.netty.util; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; From 08782a5ee3f0af1d890c3f7074e985513c26e96d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 14:11:31 +0100 Subject: [PATCH 0012/2070] Format with 140 chars lines --- .../AsyncHandlerExtensions.java | 2 +- .../org/asynchttpclient/AsyncHttpClient.java | 38 +++--- .../AsyncHttpClientConfig.java | 3 +- .../AsyncHttpClientConfigBean.java | 4 +- .../AsyncHttpProviderConfig.java | 2 +- .../BodyDeferringAsyncHandler.java | 21 ++-- .../ConnectionPoolKeyStrategy.java | 2 +- .../asynchttpclient/HttpResponseBodyPart.java | 4 +- .../asynchttpclient/HttpResponseHeaders.java | 1 - .../asynchttpclient/HttpResponseStatus.java | 2 +- .../java/org/asynchttpclient/ProxyServer.java | 3 +- .../main/java/org/asynchttpclient/Realm.java | 15 +-- .../java/org/asynchttpclient/Request.java | 2 + .../asynchttpclient/RequestBuilderBase.java | 3 +- .../ResumableBodyConsumer.java | 1 - .../asynchttpclient/SignatureCalculator.java | 3 +- .../SimpleAsyncHttpClient.java | 49 ++++---- .../consumers/AppendableBodyConsumer.java | 6 +- .../consumers/FileBodyConsumer.java | 4 +- .../consumers/OutputStreamBodyConsumer.java | 4 +- .../org/asynchttpclient/cookie/Cookie.java | 14 ++- .../extra/AsyncHandlerWrapper.java | 106 ++++++++-------- .../extra/ThrottleRequestFilter.java | 70 +++++------ .../generators/FileBodyGenerator.java | 3 +- .../listenable/ExecutionList.java | 6 +- .../multipart/AbstractFilePart.java | 3 +- .../multipart/CounterPartVisitor.java | 4 +- .../multipart/FilePartStallHandler.java | 78 ++++++------ .../multipart/MultipartUtils.java | 6 +- .../multipart/OutputStreamPartVisitor.java | 8 +- .../asynchttpclient/multipart/StringPart.java | 2 +- .../org/asynchttpclient/ntlm/NTLMEngine.java | 117 ++++++------------ .../asynchttpclient/oauth/ConsumerKey.java | 6 +- .../oauth/OAuthSignatureCalculator.java | 21 ++-- .../asynchttpclient/oauth/RequestToken.java | 6 +- .../asynchttpclient/oauth/ThreadSafeHMAC.java | 3 +- .../resumable/ResumableAsyncHandler.java | 6 +- .../asynchttpclient/spnego/SpnegoEngine.java | 9 +- .../util/AsyncHttpProviderUtils.java | 18 +-- .../util/AuthenticatorUtils.java | 21 ++-- .../java/org/asynchttpclient/util/Base64.java | 6 +- .../org/asynchttpclient/util/DateUtil.java | 24 ++-- .../org/asynchttpclient/util/ProxyUtils.java | 26 ++-- .../org/asynchttpclient/util/SslUtils.java | 37 +++--- .../util/StandardCharsets.java | 2 +- .../asynchttpclient/util/UTF8UrlEncoder.java | 5 +- .../webdav/WebDavCompletionHandlerBase.java | 8 +- .../websocket/DefaultWebSocketListener.java | 17 +-- .../websocket/WebSocketByteListener.java | 1 - .../websocket/WebSocketUpgradeHandler.java | 3 +- .../providers/netty/DiscardEvent.java | 4 +- .../netty/NettyAsyncHttpProvider.java | 6 +- .../netty/NettyAsyncHttpProviderConfig.java | 13 +- .../providers/netty/channel/ChannelPool.java | 16 +-- .../providers/netty/channel/Channels.java | 20 +-- .../netty/channel/DefaultChannelPool.java | 25 ++-- .../netty/future/NettyResponseFuture.java | 13 +- .../providers/netty/handler/HttpProtocol.java | 73 ++++++----- .../providers/netty/handler/Processor.java | 24 ++-- .../providers/netty/handler/Protocol.java | 23 ++-- .../netty/handler/WebSocketProtocol.java | 24 ++-- .../netty/request/NettyConnectListener.java | 6 +- .../netty/request/NettyRequestFactory.java | 9 +- .../netty/request/NettyRequestSender.java | 77 ++++++++---- .../netty/request/ProgressListener.java | 9 +- .../request/body/FeedableBodyGenerator.java | 9 +- .../request/body/NettyInputStreamBody.java | 21 ++-- .../IdleConnectionTimeoutTimerTask.java | 9 +- .../timeout/RequestTimeoutTimerTask.java | 9 +- .../request/timeout/TimeoutTimerTask.java | 6 +- .../netty/response/EagerResponseBodyPart.java | 19 ++- .../netty/response/LazyResponseBodyPart.java | 19 ++- .../netty/response/NettyResponse.java | 5 +- .../netty/response/ResponseHeaders.java | 8 +- .../netty/response/ResponseStatus.java | 8 +- .../providers/netty/util/ByteBufUtil.java | 5 +- .../netty/util/CleanupChannelGroup.java | 12 +- .../providers/netty/util/HttpUtil.java | 8 +- .../providers/netty/ws/WebSocketUtil.java | 1 + .../netty/NettyAsyncProviderBasicTest.java | 2 +- .../netty/NettyAsyncProviderPipelineTest.java | 3 +- .../providers/netty/NettyBasicAuthTest.java | 2 +- .../netty/NettyConnectionPoolTest.java | 8 +- .../netty/NettyProxyTunnellingTest.java | 2 +- .../NettyRequestThrottleTimeoutTest.java | 48 +++---- .../netty/NettyRetryRequestTest.java | 2 +- .../netty/NettySimpleAsyncHttpClientTest.java | 1 + 87 files changed, 699 insertions(+), 655 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java index 1991d0aba1..fd4a5bf79e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java @@ -34,7 +34,7 @@ public interface AsyncHandlerExtensions { * Currently only supported by the Netty provider. */ void onRequestSent(); - + /** * Notify the callback every time a request is being retried. */ diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java index de5145c017..8a2f58294d 100755 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java @@ -149,9 +149,9 @@ public class AsyncHttpClient implements Closeable { * Providers that will be searched for, on the classpath, in order when no * provider is explicitly specified by the developer. */ - private static final String[] DEFAULT_PROVIDERS = { - "org.asynchttpclient.providers.netty.NettyAsyncHttpProvider", - "org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider" + private static final String[] DEFAULT_PROVIDERS = {// + "org.asynchttpclient.providers.netty.NettyAsyncHttpProvider",/**/ + "org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider"// }; private final AsyncHttpProvider httpProvider; @@ -174,7 +174,6 @@ public class AsyncHttpClient implements Closeable { *

    *
  • netty
  • *
  • grizzly
  • - *
  • JDK
  • *
* * If none of those providers are found, then the engine will throw an IllegalStateException. @@ -367,7 +366,6 @@ public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureC } } - /** * Return the asynchronous {@link AsyncHttpProvider} * @@ -565,7 +563,8 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h * @throws IOException */ public ListenableFuture executeRequest(Request request) throws IOException { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(new AsyncCompletionHandlerBase()).request(request).build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(new AsyncCompletionHandlerBase()) + .request(request).build(); fc = preProcessRequest(fc); return httpProvider.execute(fc.getRequest(), fc.getAsyncHandler()); } @@ -577,7 +576,7 @@ public ListenableFuture executeRequest(Request request) throws IOExcep * @return {@link FilterContext} */ private FilterContext preProcessRequest(FilterContext fc) throws IOException { - for (RequestFilter asyncFilter: config.getRequestFilters()) { + for (RequestFilter asyncFilter : config.getRequestFilters()) { try { fc = asyncFilter.filter(fc); if (fc == null) { @@ -605,36 +604,31 @@ private FilterContext preProcessRequest(FilterContext fc) throws IOExc } @SuppressWarnings("unchecked") - private static AsyncHttpProvider loadProvider(final String className, - final AsyncHttpClientConfig config) { + private static AsyncHttpProvider loadProvider(final String className, final AsyncHttpClientConfig config) { try { - Class providerClass = (Class) Thread.currentThread() - .getContextClassLoader().loadClass(className); - return providerClass.getDeclaredConstructor( - new Class[]{AsyncHttpClientConfig.class}).newInstance(config); - } catch (Throwable t) { + Class providerClass = (Class) Thread.currentThread().getContextClassLoader() + .loadClass(className); + return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(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("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) - AsyncHttpClient.class.getClassLoader().loadClass(className); - return providerClass.getDeclaredConstructor( - new Class[]{AsyncHttpClientConfig.class}).newInstance(config); + Class providerClass = (Class) AsyncHttpClient.class.getClassLoader().loadClass( + className); + return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(config); } catch (Throwable ignored) { } } return null; } - private static AsyncHttpProvider loadDefaultProvider(String[] providerClassNames, - AsyncHttpClientConfig config) { + private static AsyncHttpProvider loadDefaultProvider(String[] providerClassNames, AsyncHttpClientConfig config) { AsyncHttpProvider provider; for (final String className : providerClassNames) { provider = loadProvider(className, config); diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 41bd4240c3..0140c16d23 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -566,7 +566,8 @@ public static class Builder { 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 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); diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 4f917df0cb..3f92d0536a 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -27,7 +27,7 @@ import java.util.concurrent.ThreadFactory; /** - * Simple JavaBean version of {@link AsyncHttpClientConfig} + * Simple JavaBean version of {@link AsyncHttpClientConfig} */ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig { @@ -55,7 +55,7 @@ void configureDefaults() { compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "AsyncHttpClient/" + AHC_VERSION); ioThreadMultiplier = Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2); - + boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); if (useProxySelector) { diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java index 48b9cd565a..8ba404b98b 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java +++ b/api/src/main/java/org/asynchttpclient/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); + public AsyncHttpProviderConfig addProperty(U name, V value); /** * Return the value associated with the property's name diff --git a/api/src/main/java/org/asynchttpclient/BodyDeferringAsyncHandler.java b/api/src/main/java/org/asynchttpclient/BodyDeferringAsyncHandler.java index f26923b758..4ab5b30beb 100644 --- a/api/src/main/java/org/asynchttpclient/BodyDeferringAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/BodyDeferringAsyncHandler.java @@ -72,8 +72,7 @@ *
*/ public class BodyDeferringAsyncHandler implements AsyncHandler { - private final Response.ResponseBuilder - responseBuilder = new Response.ResponseBuilder(); + private final Response.ResponseBuilder responseBuilder = new Response.ResponseBuilder(); private final CountDownLatch headersArrived = new CountDownLatch(1); @@ -115,21 +114,18 @@ public void onThrowable(Throwable t) { } } - public STATE onStatusReceived(HttpResponseStatus responseStatus) - throws Exception { + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { responseBuilder.reset(); responseBuilder.accumulate(responseStatus); return STATE.CONTINUE; } - public STATE onHeadersReceived(HttpResponseHeaders headers) - throws Exception { + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { responseBuilder.accumulate(headers); return STATE.CONTINUE; } - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) - throws Exception { + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { // body arrived, flush headers if (!responseSet) { response = responseBuilder.build(); @@ -230,8 +226,7 @@ public static class BodyDeferringInputStream extends FilterInputStream { private final BodyDeferringAsyncHandler bdah; - public BodyDeferringInputStream(final Future future, - final BodyDeferringAsyncHandler bdah, final InputStream in) { + public BodyDeferringInputStream(final Future future, final BodyDeferringAsyncHandler bdah, final InputStream in) { super(in); this.future = future; this.bdah = bdah; @@ -263,8 +258,7 @@ public void close() throws IOException { * @return a {@link Response} * @throws InterruptedException */ - public Response getAsapResponse() throws InterruptedException, - IOException { + public Response getAsapResponse() throws InterruptedException, IOException { return bdah.getResponse(); } @@ -276,8 +270,7 @@ public Response getAsapResponse() throws InterruptedException, * @throws InterruptedException * @throws ExecutionException */ - public Response getLastResponse() throws InterruptedException, - ExecutionException { + public Response getLastResponse() throws InterruptedException, ExecutionException { return future.get(); } } diff --git a/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java b/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java index 12e9bafb22..adf626f307 100644 --- a/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java +++ b/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java @@ -19,5 +19,5 @@ public interface ConnectionPoolKeyStrategy { - String getKey(URI uri, ProxyServer proxy); + String getKey(URI uri, ProxyServer proxy); } diff --git a/api/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java b/api/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java index 173f4d384a..b7ab7c7e9f 100644 --- a/api/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java +++ b/api/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java @@ -31,7 +31,7 @@ public abstract class HttpResponseBodyPart { * @since 2.0.0 */ public abstract int length(); - + /** * Return the response body's part bytes received. * @@ -45,7 +45,7 @@ public abstract class HttpResponseBodyPart { * @since 2.0.0 */ public abstract InputStream readBodyPartBytes(); - + /** * Write the available bytes to the {@link java.io.OutputStream} * diff --git a/api/src/main/java/org/asynchttpclient/HttpResponseHeaders.java b/api/src/main/java/org/asynchttpclient/HttpResponseHeaders.java index 5ecc6898c3..b573fd8766 100644 --- a/api/src/main/java/org/asynchttpclient/HttpResponseHeaders.java +++ b/api/src/main/java/org/asynchttpclient/HttpResponseHeaders.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; - /** * A class that represent the HTTP headers. */ diff --git a/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java b/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java index b2e5b0d7ab..d57a005441 100644 --- a/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java +++ b/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java @@ -40,7 +40,7 @@ public HttpResponseStatus(URI uri, AsyncHttpClientConfig config) { public final URI getUri() { return uri; } - + /** * Prepare a {@link Response} * diff --git a/api/src/main/java/org/asynchttpclient/ProxyServer.java b/api/src/main/java/org/asynchttpclient/ProxyServer.java index ba8de97018..f5c2f6e458 100644 --- a/api/src/main/java/org/asynchttpclient/ProxyServer.java +++ b/api/src/main/java/org/asynchttpclient/ProxyServer.java @@ -60,7 +60,7 @@ public String toString() { private Charset charset = StandardCharsets.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) { + public ProxyServer(final Protocol protocol, final String host, final int port, String principal, String password) { this.protocol = protocol; this.host = host; this.port = port; @@ -151,4 +151,3 @@ public String toString() { return protocol + "://" + host + ":" + port; } } - diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index aea105fa0d..8676bdc2eb 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -55,8 +55,9 @@ public enum AuthScheme { DIGEST, BASIC, NTLM, SPNEGO, KERBEROS, NONE } - private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, String qop, String nc, String cnonce, - String uri, String method, boolean usePreemptiveAuth, String domain, String enc, String host, boolean messageType2Received, String opaque) { + private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, + String qop, String nc, String cnonce, String uri, String method, boolean usePreemptiveAuth, String domain, String enc, + String host, boolean messageType2Received, String opaque) { this.principal = principal; this.password = password; @@ -212,9 +213,9 @@ public boolean equals(Object o) { @Override public String toString() { - return "Realm{" + "principal='" + principal + '\'' + ", scheme=" + scheme + ", realmName='" + realmName + '\'' + ", nonce='" + nonce + '\'' + ", algorithm='" + algorithm - + '\'' + ", response='" + response + '\'' + ", qop='" + qop + '\'' + ", nc='" + nc + '\'' + ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' - + ", methodName='" + methodName + '\'' + '}'; + return "Realm{" + "principal='" + principal + '\'' + ", scheme=" + scheme + ", realmName='" + realmName + '\'' + ", nonce='" + + nonce + '\'' + ", algorithm='" + algorithm + '\'' + ", response='" + response + '\'' + ", qop='" + qop + '\'' + ", nc='" + + nc + '\'' + ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' + ", methodName='" + methodName + '\'' + '}'; } @Override @@ -569,8 +570,8 @@ public Realm build() { newResponse(); } - return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName, usePreemptive, domain, enc, host, - messageType2Received, opaque); + return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName, + usePreemptive, domain, enc, host, messageType2Received, opaque); } } } diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 488b97b7ee..2dd3864b98 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -54,7 +54,9 @@ public interface Request { public String getUrl(); public URI getOriginalURI(); + public URI getURI(); + public URI getRawURI(); /** diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 976c1867c5..e9b6081bd0 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -408,7 +408,8 @@ private void addQueryParameters(URI uri) { if (useRawUrl) { addQueryParameter(query.substring(0, pos), query.substring(pos + 1)); } else { - addQueryParameter(URLDecoder.decode(query.substring(0, pos), StandardCharsets.UTF_8.name()), URLDecoder.decode(query.substring(pos + 1), StandardCharsets.UTF_8.name())); + addQueryParameter(URLDecoder.decode(query.substring(0, pos), StandardCharsets.UTF_8.name()), + URLDecoder.decode(query.substring(pos + 1), StandardCharsets.UTF_8.name())); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); diff --git a/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java b/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java index 4fa0025909..3f327446c9 100644 --- a/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java @@ -34,5 +34,4 @@ public interface ResumableBodyConsumer extends BodyConsumer { */ long getTransferredBytes() throws IOException; - } diff --git a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java index baa96ba3c3..6e0966437f 100644 --- a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java @@ -35,6 +35,5 @@ 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); + public void calculateAndAddSignature(String url, Request request, RequestBuilderBase requestBuilder); } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index c995692ef4..3764f520ab 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -74,7 +74,9 @@ public class SimpleAsyncHttpClient implements Closeable { private final boolean derived; private final String providerClass; - private SimpleAsyncHttpClient(AsyncHttpClientConfig config, RequestBuilder requestBuilder, ThrowableHandler defaultThrowableHandler, ErrorDocumentBehaviour errorDocumentBehaviour, boolean resumeEnabled, AsyncHttpClient ahc, SimpleAHCTransferListener listener, String providerClass) { + 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; @@ -130,7 +132,8 @@ public Future post(BodyGenerator bodyGenerator, BodyConsumer bodyConsu return execute(r, bodyConsumer, null); } - public Future post(BodyGenerator bodyGenerator, BodyConsumer bodyConsumer, ThrowableHandler throwableHandler) throws IOException { + public Future post(BodyGenerator bodyGenerator, BodyConsumer bodyConsumer, ThrowableHandler throwableHandler) + throws IOException { RequestBuilder r = rebuildRequest(requestBuilder.build()); r.setMethod("POST"); r.setBody(bodyGenerator); @@ -166,7 +169,8 @@ public Future put(BodyGenerator bodyGenerator, BodyConsumer bodyConsum return execute(r, bodyConsumer, null); } - public Future put(BodyGenerator bodyGenerator, BodyConsumer bodyConsumer, ThrowableHandler throwableHandler) throws IOException { + public Future put(BodyGenerator bodyGenerator, BodyConsumer bodyConsumer, ThrowableHandler throwableHandler) + throws IOException { RequestBuilder r = rebuildRequest(requestBuilder.build()); r.setMethod("PUT"); r.setBody(bodyGenerator); @@ -277,10 +281,10 @@ 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.getUrl(), listener); - if (resumeEnabled && request.getMethod().equals("GET") && - bodyConsumer != null && bodyConsumer instanceof ResumableBodyConsumer) { + if (resumeEnabled && request.getMethod().equals("GET") && bodyConsumer != null && bodyConsumer instanceof ResumableBodyConsumer) { ResumableBodyConsumer fileBodyConsumer = (ResumableBodyConsumer) bodyConsumer; long length = fileBodyConsumer.getTransferredBytes(); fileBodyConsumer.resume(); @@ -686,15 +690,14 @@ public SimpleAsyncHttpClient build() { configBuilder.addIOExceptionFilter(new ResumableIOExceptionFilter()); - SimpleAsyncHttpClient sc = new SimpleAsyncHttpClient(configBuilder.build(), requestBuilder, defaultThrowableHandler, errorDocumentBehaviour, enableResumableDownload, ahc, listener, providerClass); + SimpleAsyncHttpClient sc = new SimpleAsyncHttpClient(configBuilder.build(), requestBuilder, defaultThrowableHandler, + errorDocumentBehaviour, enableResumableDownload, ahc, listener, providerClass); return sc; } } - private final static class ResumableBodyConsumerAsyncHandler - extends ResumableAsyncHandler - implements ProgressAsyncHandler { + private final static class ResumableBodyConsumerAsyncHandler extends ResumableAsyncHandler implements ProgressAsyncHandler { private final ProgressAsyncHandler delegate; @@ -729,7 +732,8 @@ 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, String url, SimpleAHCTransferListener listener) { this.bodyConsumer = bodyConsumer; this.exceptionHandler = exceptionHandler; this.errorDocumentBehaviour = errorDocumentBehaviour; @@ -767,7 +771,6 @@ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Excep return STATE.CONTINUE; } - /** * {@inheritDoc} */ @@ -789,20 +792,19 @@ private void closeConsumer() { } @Override - public STATE onStatusReceived(HttpResponseStatus status) - throws Exception { + public STATE onStatusReceived(HttpResponseStatus status) throws Exception { fireStatus(status); if (isErrorStatus(status)) { switch (errorDocumentBehaviour) { - case ACCUMULATE: - accumulateBody = true; - break; - case OMIT: - omitBody = true; - break; - default: - break; + case ACCUMULATE: + accumulateBody = true; + break; + case OMIT: + omitBody = true; + break; + default: + break; } } return super.onStatusReceived(status); @@ -813,8 +815,7 @@ private boolean isErrorStatus(HttpResponseStatus status) { } @Override - public STATE onHeadersReceived(HttpResponseHeaders headers) - throws Exception { + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { calculateTotal(headers); fireHeaders(headers); diff --git a/api/src/main/java/org/asynchttpclient/consumers/AppendableBodyConsumer.java b/api/src/main/java/org/asynchttpclient/consumers/AppendableBodyConsumer.java index 259fecf98e..6f84d57f6b 100644 --- a/api/src/main/java/org/asynchttpclient/consumers/AppendableBodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/consumers/AppendableBodyConsumer.java @@ -39,10 +39,8 @@ public AppendableBodyConsumer(Appendable appendable) { @Override public void consume(ByteBuffer byteBuffer) throws IOException { - appendable.append(new String(byteBuffer.array(), - byteBuffer.arrayOffset() + byteBuffer.position(), - byteBuffer.remaining(), - encoding)); + appendable + .append(new String(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining(), encoding)); } @Override diff --git a/api/src/main/java/org/asynchttpclient/consumers/FileBodyConsumer.java b/api/src/main/java/org/asynchttpclient/consumers/FileBodyConsumer.java index 8c5660b80b..5677dfdd19 100644 --- a/api/src/main/java/org/asynchttpclient/consumers/FileBodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/consumers/FileBodyConsumer.java @@ -35,9 +35,7 @@ public FileBodyConsumer(RandomAccessFile file) { @Override public void consume(ByteBuffer byteBuffer) throws IOException { // TODO: Channel.transferFrom may be a good idea to investigate. - file.write(byteBuffer.array(), - byteBuffer.arrayOffset() + byteBuffer.position(), - byteBuffer.remaining()); + file.write(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining()); } /** diff --git a/api/src/main/java/org/asynchttpclient/consumers/OutputStreamBodyConsumer.java b/api/src/main/java/org/asynchttpclient/consumers/OutputStreamBodyConsumer.java index 15f18ca0cc..65f8f85cc9 100644 --- a/api/src/main/java/org/asynchttpclient/consumers/OutputStreamBodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/consumers/OutputStreamBodyConsumer.java @@ -34,9 +34,7 @@ public OutputStreamBodyConsumer(OutputStream outputStream) { */ @Override public void consume(ByteBuffer byteBuffer) throws IOException { - outputStream.write(byteBuffer.array(), - byteBuffer.arrayOffset() + byteBuffer.position(), - byteBuffer.remaining()); + outputStream.write(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining()); } /** diff --git a/api/src/main/java/org/asynchttpclient/cookie/Cookie.java b/api/src/main/java/org/asynchttpclient/cookie/Cookie.java index de8ea526cb..66c366cfaf 100644 --- a/api/src/main/java/org/asynchttpclient/cookie/Cookie.java +++ b/api/src/main/java/org/asynchttpclient/cookie/Cookie.java @@ -14,7 +14,8 @@ public class Cookie { - public static Cookie newValidCookie(String name, String value, String rawValue, String domain, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { + public static Cookie newValidCookie(String name, String value, String rawValue, String domain, String path, long expires, int maxAge, + boolean secure, boolean httpOnly) { if (name == null) { throw new NullPointerException("name"); @@ -41,7 +42,8 @@ public static Cookie newValidCookie(String name, String value, String rawValue, case ',': case ';': case '=': - throw new IllegalArgumentException("name contains one of the following prohibited characters: " + "=,; \\t\\r\\n\\v\\f: " + name); + throw new IllegalArgumentException("name contains one of the following prohibited characters: " + "=,; \\t\\r\\n\\v\\f: " + + name); } } @@ -76,7 +78,8 @@ private static String validateValue(String name, String value) { case '\f': case 0x0b: case ';': - throw new IllegalArgumentException(name + " contains one of the following prohibited characters: " + ";\\r\\n\\f\\v (" + value + ')'); + throw new IllegalArgumentException(name + " contains one of the following prohibited characters: " + ";\\r\\n\\f\\v (" + + value + ')'); } } return value; @@ -92,7 +95,8 @@ private static String validateValue(String name, String value) { private final boolean secure; private final boolean httpOnly; - public Cookie(String name, String value, String rawValue, String domain, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { + 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; @@ -127,7 +131,7 @@ public String getPath() { public long getExpires() { return expires; } - + public int getMaxAge() { return maxAge; } diff --git a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java index 3ff4d806f6..c9b2f0ae7b 100644 --- a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java +++ b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java @@ -11,63 +11,63 @@ public class AsyncHandlerWrapper implements AsyncHandler { - private final static Logger logger = LoggerFactory.getLogger(AsyncHandlerWrapper.class); - private final AsyncHandler asyncHandler; - private final Semaphore available; + private final static Logger logger = LoggerFactory.getLogger(AsyncHandlerWrapper.class); + private final AsyncHandler asyncHandler; + private final Semaphore available; - public AsyncHandlerWrapper(AsyncHandler asyncHandler, Semaphore available) { - this.asyncHandler = asyncHandler; - this.available = available; - } + public AsyncHandlerWrapper(AsyncHandler asyncHandler, Semaphore available) { + this.asyncHandler = asyncHandler; + this.available = available; + } - /** - * {@inheritDoc} - */ - @Override - public void onThrowable(Throwable t) { - try { - asyncHandler.onThrowable(t); - } finally { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); - } - } - } + /** + * {@inheritDoc} + */ + @Override + public void onThrowable(Throwable t) { + try { + asyncHandler.onThrowable(t); + } finally { + available.release(); + if (logger.isDebugEnabled()) { + logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); + } + } + } - /** - * {@inheritDoc} - */ - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - return asyncHandler.onBodyPartReceived(bodyPart); - } + /** + * {@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 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 STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + return asyncHandler.onHeadersReceived(headers); + } - /** - * {@inheritDoc} - */ - @Override - public T onCompleted() throws Exception { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status {}", available.availablePermits()); - } - return asyncHandler.onCompleted(); - } + /** + * {@inheritDoc} + */ + @Override + public T onCompleted() throws Exception { + available.release(); + if (logger.isDebugEnabled()) { + logger.debug("Current Throttling Status {}", available.availablePermits()); + } + return asyncHandler.onCompleted(); + } } \ No newline at end of file diff --git a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java index 98dfd8c38d..7445af3eec 100644 --- a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java +++ b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java @@ -26,40 +26,38 @@ * 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 Semaphore available; - private final int maxWait; - - public ThrottleRequestFilter(int maxConnections) { - this(maxConnections, Integer.MAX_VALUE); - } - - public ThrottleRequestFilter(int maxConnections, int maxWait) { - this.maxWait = maxWait; - available = new Semaphore(maxConnections, true); - } - - /** - * {@inheritDoc} - */ - @Override - public FilterContext filter(FilterContext ctx) throws FilterException { - - try { - 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", ctx.getRequest(), - ctx.getAsyncHandler())); - } - } catch (InterruptedException e) { - throw new FilterException(String.format("Interrupted Request %s with AsyncHandler %s", ctx.getRequest(), - ctx.getAsyncHandler())); - } - - return new FilterContext.FilterContextBuilder(ctx).asyncHandler( - new AsyncHandlerWrapper(ctx.getAsyncHandler(), available)).build(); - } + private final static Logger logger = LoggerFactory.getLogger(ThrottleRequestFilter.class); + private final Semaphore available; + private final int maxWait; + + public ThrottleRequestFilter(int maxConnections) { + this(maxConnections, Integer.MAX_VALUE); + } + + public ThrottleRequestFilter(int maxConnections, int maxWait) { + this.maxWait = maxWait; + available = new Semaphore(maxConnections, true); + } + + /** + * {@inheritDoc} + */ + @Override + public FilterContext filter(FilterContext ctx) throws FilterException { + + try { + 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", + ctx.getRequest(), ctx.getAsyncHandler())); + } + } catch (InterruptedException e) { + throw new FilterException(String.format("Interrupted Request %s with AsyncHandler %s", ctx.getRequest(), ctx.getAsyncHandler())); + } + + return new FilterContext.FilterContextBuilder(ctx).asyncHandler(new AsyncHandlerWrapper(ctx.getAsyncHandler(), available)) + .build(); + } } \ No newline at end of file diff --git a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java index 2a3ec0761b..007a993206 100644 --- a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java +++ b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java @@ -85,8 +85,7 @@ public long getContentLength() { return length; } - public long read(ByteBuffer buffer) - throws IOException { + public long read(ByteBuffer buffer) throws IOException { return channel.read(buffer); } diff --git a/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java b/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java index a6e3cba837..99347e792f 100644 --- a/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java +++ b/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java @@ -48,8 +48,7 @@ public final class ExecutionList implements Runnable { // Logger to log exceptions caught when running runnables. - private static final Logger log = - Logger.getLogger(ExecutionList.class.getName()); + private static final Logger log = Logger.getLogger(ExecutionList.class.getName()); // The runnable,executor pairs to execute. private final Queue runnables = new LinkedBlockingQueue(); @@ -130,8 +129,7 @@ void execute() { // Log it and keep going, bad runnable and/or executor. Don't // punish the other runnables if we're given a bad one. We only // catch RuntimeException because we want Errors to propagate up. - log.log(Level.SEVERE, "RuntimeException while executing runnable " - + runnable + " with executor " + executor, e); + log.log(Level.SEVERE, "RuntimeException while executing runnable " + runnable + " with executor " + executor, e); } } } diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index 8057f9910e..14edabbd52 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -63,7 +63,8 @@ public abstract class AbstractFilePart extends PartBase { * @param contentId */ public AbstractFilePart(String name, String contentType, String charset, String contentId) { - super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); + super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? DEFAULT_CHARSET : charset, + DEFAULT_TRANSFER_ENCODING, contentId); } public abstract String getFileName(); diff --git a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java index 993f917861..738db27144 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java @@ -20,12 +20,12 @@ public class CounterPartVisitor implements PartVisitor { private long count = 0L; - + @Override public void withBytes(byte[] bytes) throws IOException { count += bytes.length; } - + public long getCount() { return count; } diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java b/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java index c358ce1731..ed89723027 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java @@ -19,43 +19,43 @@ * @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; + 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/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index cfa188ff96..e73cb802a6 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java @@ -47,7 +47,8 @@ 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); + private static byte[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + .getBytes(StandardCharsets.US_ASCII); private MultipartUtils() { } @@ -72,7 +73,8 @@ public static MultipartBody newMultipartBody(List parts, FluentCaseInsensi if (boundaryLocation != -1) { // boundary defined in existing Content-Type contentType = contentTypeHeader; - multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim()).getBytes(StandardCharsets.US_ASCII); + multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim()) + .getBytes(StandardCharsets.US_ASCII); } else { // generate boundary and append it to existing Content-Type multipartBoundary = generateMultipartBoundary(); diff --git a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java index c65355075c..7f57532459 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java @@ -21,16 +21,16 @@ public class OutputStreamPartVisitor implements PartVisitor { private final OutputStream out; - + public OutputStreamPartVisitor(OutputStream out) { this.out = out; } - + @Override - public void withBytes(byte[] bytes) throws IOException{ + public void withBytes(byte[] bytes) throws IOException { out.write(bytes); } - + public OutputStream getOutputStream() { return out; } diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index 1901cd5c85..1dad2f0be3 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -92,7 +92,7 @@ protected void sendData(OutputStream out) throws IOException { protected long getDataLength() { return content.length; } - + public byte[] getBytes(byte[] boundary) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); write(outputStream, boundary); diff --git a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java b/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java index f3bcf9406d..687759f755 100644 --- a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java +++ b/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java @@ -110,16 +110,15 @@ 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 (message == null || message.trim().length() == 0) { response = getType1Message(host, domain); } else { 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()); } return response; } @@ -155,12 +154,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); } @@ -207,8 +204,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 { @@ -221,8 +217,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; @@ -266,8 +261,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); } @@ -280,8 +274,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); } @@ -299,9 +292,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); @@ -318,8 +310,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); } @@ -335,8 +327,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); @@ -470,8 +461,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); @@ -491,9 +481,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. @@ -503,8 +493,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; @@ -553,8 +542,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 { @@ -595,16 +583,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; } @@ -775,12 +762,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); @@ -826,9 +812,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 @@ -899,9 +883,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; @@ -915,8 +898,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) { @@ -1013,11 +995,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); @@ -1129,8 +1109,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); } @@ -1234,8 +1213,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 @@ -1292,27 +1270,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/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java b/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java index 5b270ac2d1..1962798330 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java +++ b/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java @@ -63,8 +63,10 @@ public int hashCode() { @Override public boolean equals(Object o) { - if (o == this) return true; - if (o == null || o.getClass() != getClass()) return false; + if (o == this) + return true; + if (o == null || o.getClass() != getClass()) + return false; ConsumerKey other = (ConsumerKey) o; return key.equals(other.key) && secret.equals(other.secret); } diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java index 82d9b5c45b..b13f5a9c58 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java @@ -40,8 +40,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"; @@ -94,8 +93,8 @@ 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) { + public String calculateSignature(String method, String baseURL, long oauthTimestamp, String nonce, FluentStringsMap formParams, + FluentStringsMap queryParams) { StringBuilder signedText = new StringBuilder(100); signedText.append(method); // POST / GET etc (nothing to URL encode) signedText.append('&'); @@ -186,7 +185,7 @@ private synchronized String generateNonce() { random.nextBytes(nonceBuffer); // let's use base64 encoding over hex, slightly more compact than hex or decimals return Base64.encode(nonceBuffer); -// return String.valueOf(Math.abs(random.nextLong())); + // return String.valueOf(Math.abs(random.nextLong())); } /** @@ -262,13 +261,17 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; Parameter parameter = (Parameter) o; - if (!key.equals(parameter.key)) return false; - if (!value.equals(parameter.value)) return false; + if (!key.equals(parameter.key)) + return false; + if (!value.equals(parameter.value)) + return false; return true; } diff --git a/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java b/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java index 78b3758b4c..2fd02c4244 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java +++ b/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java @@ -65,8 +65,10 @@ public int hashCode() { @Override public boolean equals(Object o) { - if (o == this) return true; - if (o == null || o.getClass() != getClass()) return false; + if (o == this) + return true; + if (o == null || o.getClass() != getClass()) + return false; RequestToken other = (RequestToken) o; return key.equals(other.key) && secret.equals(other.secret); } diff --git a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java b/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java index ba4cb6a089..028020f758 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java +++ b/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java @@ -37,7 +37,8 @@ public class ThreadSafeHMAC { private final Mac mac; public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) { - byte[] keyBytes = (UTF8UrlEncoder.encode(consumerAuth.getSecret()) + "&" + UTF8UrlEncoder.encode(userAuth.getSecret())).getBytes(StandardCharsets.UTF_8); + byte[] keyBytes = (UTF8UrlEncoder.encode(consumerAuth.getSecret()) + "&" + UTF8UrlEncoder.encode(userAuth.getSecret())) + .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/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index 119a55538d..6b301b7f93 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -51,10 +51,8 @@ public class ResumableAsyncHandler implements AsyncHandler { private final boolean accumulateBody; private ResumableListener resumableListener = new NULLResumableListener(); - private ResumableAsyncHandler(long byteTransferred, - ResumableProcessor resumableProcessor, - AsyncHandler decoratedAsyncHandler, - boolean accumulateBody) { + private ResumableAsyncHandler(long byteTransferred, ResumableProcessor resumableProcessor, + AsyncHandler decoratedAsyncHandler, boolean accumulateBody) { this.byteTransferred = new AtomicLong(byteTransferred); diff --git a/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java b/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java index aa42c011aa..dc371e0294 100644 --- a/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java +++ b/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java @@ -105,7 +105,8 @@ public String generateToken(String server) throws Throwable { try { GSSManager manager = GSSManager.getInstance(); GSSName serverName = manager.createName("HTTP@" + server, GSSName.NT_HOSTBASED_SERVICE); - gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null, GSSContext.DEFAULT_LIFETIME); + gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null, + GSSContext.DEFAULT_LIFETIME); gssContext.requestMutualAuth(true); gssContext.requestCredDeleg(true); } catch (GSSException ex) { @@ -126,7 +127,8 @@ public String generateToken(String server) throws Throwable { negotiationOid = new Oid(KERBEROS_OID); GSSManager manager = GSSManager.getInstance(); GSSName serverName = manager.createName("HTTP@" + server, GSSName.NT_HOSTBASED_SERVICE); - gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null, GSSContext.DEFAULT_LIFETIME); + gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null, + GSSContext.DEFAULT_LIFETIME); gssContext.requestMutualAuth(true); gssContext.requestCredDeleg(true); } @@ -160,7 +162,8 @@ public String generateToken(String server) throws Throwable { throw new Exception(gsse.getMessage(), gsse); if (gsse.getMajor() == GSSException.NO_CRED) throw new Exception(gsse.getMessage(), gsse); - if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN || gsse.getMajor() == GSSException.DUPLICATE_TOKEN || gsse.getMajor() == GSSException.OLD_TOKEN) + if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN || gsse.getMajor() == GSSException.DUPLICATE_TOKEN + || gsse.getMajor() == GSSException.OLD_TOKEN) throw new Exception(gsse.getMessage(), gsse); // other error throw new Exception(gsse.getMessage()); diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index cbc46cec57..386319b2a9 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -41,8 +41,10 @@ public class AsyncHttpProviderUtils { public static final void validateSupportedScheme(URI uri) { final String scheme = uri.getScheme(); - if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws") && !scheme.equalsIgnoreCase("wss")) { - throw new IllegalArgumentException("The URI scheme, of the URI " + uri + ", must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss'"); + if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws") + && !scheme.equalsIgnoreCase("wss")) { + throw new IllegalArgumentException("The URI scheme, of the URI " + uri + + ", must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss'"); } } @@ -169,8 +171,10 @@ public final static URI getRedirectUri(URI uri, String location) { 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'"); + 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(); @@ -184,9 +188,9 @@ public final static int getPort(URI uri) { } 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(); + 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) { diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index 7b79ee9b2a..f8957cb443 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -50,17 +50,16 @@ public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgor return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); } - public static String computeDigestAuthentication(ProxyServer proxy) { - try{ - StringBuilder builder = new StringBuilder().append("Digest "); - construct(builder, "username", proxy.getPrincipal(),true); - return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); - } - catch (Exception e){ - e.printStackTrace(); - } - return null; - } + public static String computeDigestAuthentication(ProxyServer proxy) { + try { + StringBuilder builder = new StringBuilder().append("Digest "); + construct(builder, "username", proxy.getPrincipal(), true); + return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } private static StringBuilder construct(StringBuilder builder, String name, String value) { return construct(builder, name, value, false); diff --git a/api/src/main/java/org/asynchttpclient/util/Base64.java b/api/src/main/java/org/asynchttpclient/util/Base64.java index c6141d0654..c38ace7e39 100644 --- a/api/src/main/java/org/asynchttpclient/util/Base64.java +++ b/api/src/main/java/org/asynchttpclient/util/Base64.java @@ -80,10 +80,8 @@ public static String encode(byte[] bytes) { // first, handle complete chunks (fast loop) int i = 0; - for (int end = bytes.length - 2; i < end; ) { - int chunk = ((bytes[i++] & 0xFF) << 16) - | ((bytes[i++] & 0xFF) << 8) - | (bytes[i++] & 0xFF); + for (int end = bytes.length - 2; i < end;) { + int chunk = ((bytes[i++] & 0xFF) << 16) | ((bytes[i++] & 0xFF) << 8) | (bytes[i++] & 0xFF); buf.append(lookup[chunk >> 18]); buf.append(lookup[(chunk >> 12) & 0x3F]); buf.append(lookup[(chunk >> 6) & 0x3F]); diff --git a/api/src/main/java/org/asynchttpclient/util/DateUtil.java b/api/src/main/java/org/asynchttpclient/util/DateUtil.java index dfc0d55ef6..549174f755 100644 --- a/api/src/main/java/org/asynchttpclient/util/DateUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/DateUtil.java @@ -78,8 +78,8 @@ public class DateUtil { */ 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 Collection DEFAULT_PATTERNS = Arrays.asList(new String[] { PATTERN_ASCTIME, PATTERN_RFC1036, + PATTERN_RFC1123 }); private static final Date DEFAULT_TWO_DIGIT_YEAR_START; @@ -112,8 +112,7 @@ public static Date parseDate(String dateValue) throws DateParseException { * @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 { + public static Date parseDate(String dateValue, Collection dateFormats) throws DateParseException { return parseDate(dateValue, dateFormats, null); } @@ -129,11 +128,7 @@ public static Date parseDate(String dateValue, Collection dateFormats) * @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 { + public static Date parseDate(String dateValue, Collection dateFormats, Date startDate) throws DateParseException { if (dateValue == null) { throw new IllegalArgumentException("dateValue is null"); @@ -146,10 +141,7 @@ public static Date parseDate( } // trim single quotes around date if present // see issue #5279 - if (dateValue.length() > 1 - && dateValue.startsWith("'") - && dateValue.endsWith("'") - ) { + if (dateValue.length() > 1 && dateValue.startsWith("'") && dateValue.endsWith("'")) { dateValue = dateValue.substring(1, dateValue.length() - 1); } @@ -199,8 +191,10 @@ 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 IllegalArgumentException("date is null"); + if (pattern == null) + throw new IllegalArgumentException("pattern is null"); SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US); formatter.setTimeZone(GMT); diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index 9e06f22858..a940da8ea6 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -86,7 +86,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r } return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer; } - + /** * Checks whether proxy should be used according to nonProxyHosts settings of it, or we want to go directly to * target host. If null proxy is passed in, this method returns true -- since there is NO proxy, we @@ -204,18 +204,18 @@ public ProxyServer select(URI uri) { // 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.getHostName(), address.getPort()); - } - case DIRECT: - return null; - default: - log.warn("ProxySelector returned proxy type that we don't know how to use: " + proxy.type()); - break; + 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.getHostName(), address.getPort()); + } + case DIRECT: + return null; + default: + log.warn("ProxySelector returned proxy type that we don't know how to use: " + proxy.type()); + break; } } } diff --git a/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index 34a41e34e3..29c7b70011 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -36,10 +36,9 @@ */ public class SslUtils { - private static SSLContext context = null; + private static SSLContext context = null; - public static SSLEngine getSSLEngine() - throws GeneralSecurityException, IOException { + public static SSLEngine getSSLEngine() throws GeneralSecurityException, IOException { SSLEngine engine = null; SSLContext context = getSSLContext(); @@ -51,41 +50,35 @@ public static SSLEngine getSSLEngine() return engine; } - public static SSLContext getSSLContext() - throws GeneralSecurityException, IOException { - if (context == null) { + public static SSLContext getSSLContext() throws GeneralSecurityException, IOException { + if (context == null) { SSLConfig config = new SSLConfig(); - if (config.keyStoreLocation == null - || config.trustStoreLocation == null) { + if (config.keyStoreLocation == null || config.trustStoreLocation == null) { context = getLooseSSLContext(); } else { context = getStrictSSLContext(config); } - } - return context; + } + return context; } - static SSLContext getStrictSSLContext(SSLConfig config) - throws GeneralSecurityException, IOException { + 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()); + keyStore.load(keystoreInputStream, (config.keyStorePassword == null) ? null : config.keyStorePassword.toCharArray()); } finally { keystoreInputStream.close(); } KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(config.keyManagerAlgorithm); - keyManagerFactory.init(keyStore, (config.keyManagerPassword == null) ? null - : config.keyManagerPassword.toCharArray()); + 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()); + trustStore.load(truststoreInputStream, (config.trustStorePassword == null) ? null : config.trustStorePassword.toCharArray()); } finally { truststoreInputStream.close(); } @@ -100,15 +93,13 @@ static SSLContext getStrictSSLContext(SSLConfig config) return context; } - static SSLContext getLooseSSLContext() - throws GeneralSecurityException { + static SSLContext getLooseSSLContext() throws GeneralSecurityException { SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[]{LooseTrustManager.INSTANCE}, new SecureRandom()); + sslContext.init(null, new TrustManager[] { LooseTrustManager.INSTANCE }, new SecureRandom()); return sslContext; } - static class LooseTrustManager - implements X509TrustManager { + static class LooseTrustManager implements X509TrustManager { public static final LooseTrustManager INSTANCE = new LooseTrustManager(); diff --git a/api/src/main/java/org/asynchttpclient/util/StandardCharsets.java b/api/src/main/java/org/asynchttpclient/util/StandardCharsets.java index 4f84ce7f8a..13eb64a40e 100644 --- a/api/src/main/java/org/asynchttpclient/util/StandardCharsets.java +++ b/api/src/main/java/org/asynchttpclient/util/StandardCharsets.java @@ -22,7 +22,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 ISO_8859_1 = Charset.forName("ISO-8859-1"); - public static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked"); + public static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked"); private StandardCharsets() { } diff --git a/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java b/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java index 6e135ce29a..765a67f368 100644 --- a/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java +++ b/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java @@ -20,8 +20,7 @@ * (as per RFC-3986, see [http://www.ietf.org/rfc/rfc3986.txt]). */ public class UTF8UrlEncoder { - private static final boolean encodeSpaceUsingPlus = - System.getProperty("com.UTF8UrlEncoder.encodeSpaceUsingPlus") != null; + private static final boolean encodeSpaceUsingPlus = System.getProperty("com.UTF8UrlEncoder.encodeSpaceUsingPlus") != null; /** * Encoding table used for figuring out ascii characters that must be escaped @@ -59,7 +58,7 @@ 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)) { + 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) { diff --git a/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java b/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java index 8badcf05de..347d5127ef 100644 --- a/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java +++ b/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java @@ -49,8 +49,7 @@ public abstract class WebDavCompletionHandlerBase implements AsyncHandler { private final Logger logger = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class); - private final List bodies = - Collections.synchronizedList(new ArrayList()); + private final List bodies = Collections.synchronizedList(new ArrayList()); private HttpResponseStatus status; private HttpResponseHeaders headers; @@ -114,7 +113,6 @@ public void onThrowable(Throwable t) { */ abstract public T onCompleted(WebDavResponse response) throws Exception; - private class HttpStatusWrapper extends HttpResponseStatus { private final HttpResponseStatus wrapped; @@ -129,11 +127,11 @@ public HttpStatusWrapper(HttpResponseStatus wrapper, String statusText, int stat 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 diff --git a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java index 218d5ab323..864bb32df8 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java @@ -20,10 +20,10 @@ * * @since 1.7.0 */ -public class DefaultWebSocketListener implements WebSocketByteListener, WebSocketTextListener, WebSocketPingListener, WebSocketPongListener { +public class DefaultWebSocketListener implements WebSocketByteListener, WebSocketTextListener, WebSocketPingListener, WebSocketPongListener { protected WebSocket webSocket; - + // -------------------------------------- Methods from WebSocketByteListener /** @@ -40,9 +40,8 @@ public void onMessage(byte[] message) { public void onFragment(byte[] fragment, boolean last) { } - // -------------------------------------- Methods from WebSocketPingListener - + /** * {@inheritDoc} */ @@ -50,19 +49,16 @@ public void onFragment(byte[] fragment, boolean last) { public void onPing(byte[] message) { } - // -------------------------------------- Methods from WebSocketPongListener - + /** * {@inheritDoc} */ @Override public void onPong(byte[] message) { } - - - // -------------------------------------- Methods from WebSocketTextListener + // -------------------------------------- Methods from WebSocketTextListener /** * {@inheritDoc} @@ -77,8 +73,7 @@ public void onMessage(String message) { @Override public void onFragment(String fragment, boolean last) { } - - + // ------------------------------------------ Methods from WebSocketListener /** diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java index 86ed261807..55f35a3f2b 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java +++ b/api/src/main/java/org/asynchttpclient/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. * diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index e88121877c..69e7664d76 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -133,7 +133,8 @@ public final void onFailure(Throwable t) { public final void onClose(WebSocket webSocket, int status, String reasonPhrase) { // Connect failure - if (this.webSocket == null) this.webSocket = webSocket; + if (this.webSocket == null) + this.webSocket = webSocket; for (WebSocketListener w : l) { if (webSocket != null) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java index 9765c34305..a8590efa73 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java @@ -12,7 +12,9 @@ */ package org.asynchttpclient.providers.netty; -// Simple marker for stopping publishing bytes. +/** + * Simple marker for stopping publishing bytes. + */ public enum DiscardEvent { INSTANCE; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java index 17091a3d49..01d71e1baf 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -53,8 +53,10 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @Override public String toString() { int availablePermits = channels.freeConnections != null ? channels.freeConnections.availablePermits() : 0; - return String.format("NettyAsyncHttpProvider4:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s", config.getMaxTotalConnections() - - availablePermits, channels.openChannels.toString(), channels.channelPool.toString()); + return String.format("NettyAsyncHttpProvider4:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s", + config.getMaxTotalConnections() - availablePermits,// + channels.openChannels.toString(),// + channels.channelPool.toString()); } @Override diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index c1b554babc..c012e6b27a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -98,17 +98,18 @@ public NettyAsyncHttpProviderConfig() { } /** - * Add a property that will be used when the AsyncHttpClient initialize its {@link org.asynchttpclient.AsyncHttpProvider} + * Add a property that will be used when the AsyncHttpClient initialize its + * {@link org.asynchttpclient.AsyncHttpProvider} * - * @param name - * the name of the property - * @param value - * the value of the property + * @param name the name of the property + * @param value the value of the property * @return this instance of AsyncHttpProviderConfig */ public NettyAsyncHttpProviderConfig addProperty(String name, Object value) { - if (name.equals(REUSE_ADDRESS) && value == Boolean.TRUE && System.getProperty("os.name").toLowerCase().contains("win")) { + if (name.equals(REUSE_ADDRESS)// + && value == Boolean.TRUE// + && System.getProperty("os.name").toLowerCase().contains("win")) { LOGGER.warn("Can't enable {} on Windows", REUSE_ADDRESS); } else { properties.put(name, value); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java index b564ce236f..b45dbf7cd1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java @@ -23,10 +23,8 @@ 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 + * @param uri a uri used to retrieve the cached connection + * @param connection an I/O connection * @return true if added. */ public boolean offer(String uri, Channel connection); @@ -34,8 +32,7 @@ public interface ChannelPool { /** * Remove the connection associated with the uri. * - * @param uri - * the uri used when invoking addConnection + * @param uri the uri used when invoking addConnection * @return the connection associated with the uri */ public Channel poll(String uri); @@ -43,15 +40,14 @@ public interface ChannelPool { /** * Remove all connections from the cache. A connection might have been associated with several uri. * - * @param connection - * a connection + * @param connection a connection * @return the true if the connection has been removed */ public 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. 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. */ diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 55b20abc16..1182ef4d5d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -18,6 +18,8 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; +import static org.asynchttpclient.providers.netty.handler.Processor.newHttpProcessor; +import static org.asynchttpclient.providers.netty.handler.Processor.newWsProcessor; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -203,8 +205,8 @@ private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException public void configureProcessor(NettyRequestSender requestSender, AtomicBoolean closed) { - final Processor httpProcessor = Processor.newHttpProcessor(config, nettyProviderConfig, requestSender, this, closed); - wsProcessor = Processor.newWsProcessor(config, nettyProviderConfig, requestSender, this, closed); + final Processor httpProcessor = newHttpProcessor(config, nettyProviderConfig, requestSender, this, closed); + wsProcessor = newWsProcessor(config, nettyProviderConfig, requestSender, this, closed); plainBootstrap.handler(new ChannelInitializer() { @Override @@ -279,7 +281,8 @@ protected void initChannel(Channel ch) throws Exception { } public Bootstrap getBootstrap(String url, boolean useSSl, boolean useProxy) { - return (url.startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); + return (url.startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) + : (useSSl ? secureBootstrap : plainBootstrap); } public void close() { @@ -301,9 +304,8 @@ public void close() { } /** - * 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. + * 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. */ public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { @@ -318,7 +320,11 @@ public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throw protected HttpClientCodec newHttpClientCodec() { if (nettyProviderConfig != null) { - return new HttpClientCodec(nettyProviderConfig.getMaxInitialLineLength(), nettyProviderConfig.getMaxHeaderSize(), nettyProviderConfig.getMaxChunkSize(), false); + return new HttpClientCodec(// + nettyProviderConfig.getMaxInitialLineLength(),// + nettyProviderConfig.getMaxHeaderSize(),// + nettyProviderConfig.getMaxChunkSize(),// + false); } else { return new HttpClientCodec(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 9a9cf76602..cfae7c3883 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -51,11 +51,20 @@ public class DefaultChannelPool implements ChannelPool { private final long maxIdleTime; public DefaultChannelPool(AsyncHttpClientConfig config, HashedWheelTimer hashedWheelTimer) { - this(config.getMaxTotalConnections(), config.getMaxConnectionPerHost(), config.getIdleConnectionInPoolTimeoutInMs(), config.isSslConnectionPoolEnabled(), config - .getMaxConnectionLifeTimeInMs(), hashedWheelTimer); + this(config.getMaxTotalConnections(),// + config.getMaxConnectionPerHost(),// + config.getIdleConnectionInPoolTimeoutInMs(),// + config.isSslConnectionPoolEnabled(),// + config.getMaxConnectionLifeTimeInMs(),// + hashedWheelTimer); } - public DefaultChannelPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, boolean sslConnectionPoolEnabled, int maxConnectionLifeTimeInMs, + public DefaultChannelPool(// + int maxTotalConnections,// + int maxConnectionPerHost,// + long maxIdleTime,// + boolean sslConnectionPoolEnabled,// + int maxConnectionLifeTimeInMs,// HashedWheelTimer hashedWheelTimer) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -157,8 +166,8 @@ public void run(Timeout timeout) throws Exception { 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); @@ -275,11 +284,7 @@ public boolean removeAll(Channel channel) { * {@inheritDoc} */ public boolean canCacheConnection() { - if (!closed.get() && maxTotalConnections != -1 && channel2IdleChannel.size() >= maxTotalConnections) { - return false; - } else { - return true; - } + return !closed.get() && (maxTotalConnections == -1 || channel2IdleChannel.size() < maxTotalConnections); } /** diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 11550f74f7..01739dc8a2 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -117,11 +117,7 @@ public NettyResponseFuture(URI uri,// this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; - if (System.getProperty(MAX_RETRY) != null) { - maxRetry = Integer.valueOf(System.getProperty(MAX_RETRY)); - } else { - maxRetry = config.getMaxRequestRetry(); - } + maxRetry = Integer.getInteger(MAX_RETRY, config.getMaxRequestRetry()); } public URI getURI() { @@ -477,13 +473,14 @@ public void setRequest(Request request) { } /** - * 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 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 canBeReplayed() { - return !isDone() && canRetry() && !isCancelled() && !(channel != null && channel.isOpen() && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); + return !isDone() && canRetry() && !isCancelled() + && !(channel != null && channel.isOpen() && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); } public long getStart() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 033e3c0b5b..61bbe02c0a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -41,6 +41,7 @@ import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.ResponseHeaders; import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; @@ -66,7 +67,8 @@ final class HttpProtocol extends Protocol { private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); - public HttpProtocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { + public HttpProtocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + NettyRequestSender requestSender) { super(channels, config, nettyConfig, requestSender); } @@ -74,8 +76,8 @@ 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) 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(); @@ -104,8 +106,8 @@ private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); } - 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; @@ -138,12 +140,13 @@ 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 { + 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); - addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost()); + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), + proxyServer.getNtlmDomain(), proxyServer.getHost()); return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) @@ -151,8 +154,8 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer .setMethodName(request.getMethod()).build(); } - 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); if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { @@ -175,7 +178,8 @@ private void finishUpdate(final NettyResponseFuture future, Channel channel, markAsDone(future, channel); } - private final boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart bodyPart) throws Exception { + private final boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart bodyPart) + throws Exception { boolean state = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; if (bodyPart.isUnderlyingConnectionToBeClosed()) { future.setKeepAlive(false); @@ -198,8 +202,8 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) th } } - private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, final NettyResponseFuture future, - ProxyServer proxyServer, final Channel channel) throws Exception { + private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, + final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws Exception { if (statusCode == UNAUTHORIZED.code() && realm != null) { List authenticateHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); @@ -218,8 +222,9 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req return true; } } else { - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(request.getURI().getPath()).setMethodName(request.getMethod()) - .setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); + newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(request.getURI().getPath()) + .setMethodName(request.getMethod()).setUsePreemptiveAuth(true) + .parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); } Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(URI.create(request.getUrl()).getPath()).build(); @@ -260,8 +265,13 @@ private boolean handleContinueAndExit(final Channel channel, final NettyResponse return false; } - private boolean handleProxyAuthenticationRequiredAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, final NettyResponseFuture future, + private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// + Realm realm,// + final Request request,// + HttpResponse response,// + final NettyResponseFuture future,// ProxyServer proxyServer) throws Exception { + if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null) { List proxyAuthenticateHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); if (!proxyAuthenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { @@ -290,15 +300,16 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode, Realm r future.setReuseChannel(true); future.setConnectAllowed(true); - requestSender.sendNextRequest(new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(newRealm).build(), future); + Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(newRealm).build(); + requestSender.sendNextRequest(nextRequest, future); return true; } } return false; } - private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Request request, HttpRequest httpRequest, HttpResponse response, final NettyResponseFuture future, - ProxyServer proxyServer, final Channel channel) throws IOException { + private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Request request, HttpRequest httpRequest, + HttpResponse response, final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws IOException { if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); @@ -322,17 +333,18 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques return false; } - private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, HttpResponseHeaders responseHeaders, - HttpResponse response) throws Exception { - if (!future.getAndSetStatusReceived(true) && (handler.onStatusReceived(status) != STATE.CONTINUE || handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE)) { + private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, + HttpResponseHeaders responseHeaders, HttpResponse response) throws Exception { + if (!future.getAndSetStatusReceived(true) + && (handler.onStatusReceived(status) != STATE.CONTINUE || handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE)) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; } return false; } - private boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, HttpRequest httpRequest, ProxyServer proxyServer, - HttpResponse response) throws Exception { + private boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, + HttpRequest httpRequest, ProxyServer proxyServer, HttpResponse response) throws Exception { // store the original headers so we can re-send all them to // the handler in case of trailing headers @@ -380,7 +392,8 @@ public void handle(final Channel channel, final NettyResponseFuture future, f HttpResponse response = future.getPendingResponse(); future.setPendingResponse(null); if (handler != null) { - if (response != null && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest(), proxyServer, response)) { + if (response != null + && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest(), proxyServer, response)) { return; } @@ -393,14 +406,16 @@ public void handle(final Channel channel, final NettyResponseFuture future, f LastHttpContent lastChunk = (LastHttpContent) chunk; HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); if (!trailingHeaders.isEmpty()) { - interrupt = handler.onHeadersReceived(new ResponseHeaders(future.getURI(), future.getHttpHeaders(), trailingHeaders)) != STATE.CONTINUE; + ResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), future.getHttpHeaders(), trailingHeaders); + interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } } ByteBuf buf = chunk.content(); try { if (!interrupt && (buf.readableBytes() > 0 || last)) { - interrupt = updateBodyAndInterrupt(future, handler, nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last)); + NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); + interrupt = updateBodyAndInterrupt(future, handler, part); } } finally { // FIXME we shouldn't need this, should we? But a leak was reported there without it?! @@ -413,7 +428,9 @@ public void handle(final Channel channel, final NettyResponseFuture future, f } } } catch (Exception t) { - if (hasIOExceptionFilters && t instanceof IOException && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { + if (hasIOExceptionFilters// + && t instanceof IOException// + && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 28f17bb924..9d31b94d36 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -49,17 +49,26 @@ public class Processor extends ChannelInboundHandlerAdapter { private final AtomicBoolean closed; private final Protocol protocol; - public static Processor newHttpProcessor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender, Channels channels, + public static Processor newHttpProcessor(AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + NettyRequestSender requestSender,// + Channels channels,// AtomicBoolean isClose) { - return new Processor(config, nettyConfig, requestSender, channels, isClose, new HttpProtocol(channels, config, nettyConfig, requestSender)); + HttpProtocol protocol = new HttpProtocol(channels, config, nettyConfig, requestSender); + return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); } - public static Processor newWsProcessor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender, Channels channels, - AtomicBoolean isClose) { - return new Processor(config, nettyConfig, requestSender, channels, isClose, new WebSocketProtocol(channels, config, nettyConfig, requestSender)); + public static Processor newWsProcessor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + NettyRequestSender requestSender, Channels channels, AtomicBoolean isClose) { + WebSocketProtocol protocol = new WebSocketProtocol(channels, config, nettyConfig, requestSender); + return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); } - private Processor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender, Channels channels, AtomicBoolean isClose, + private Processor(AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + NettyRequestSender requestSender,// + Channels channels,// + AtomicBoolean isClose,// Protocol protocol) { this.config = config; this.requestSender = requestSender; @@ -119,7 +128,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { NettyResponseFuture future = NettyResponseFuture.class.cast(attachment); future.touch(); - if (!config.getIOExceptionFilters().isEmpty() && requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), channel)) { + if (!config.getIOExceptionFilters().isEmpty() + && requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), channel)) { return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 9d3e358a68..2ac8553440 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -62,7 +62,8 @@ public abstract class Protocol { protected final boolean hasIOExceptionFilters; private final TimeConverter timeConverter; - public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { + public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + NettyRequestSender requestSender) { this.channels = channels; this.config = config; this.requestSender = requestSender; @@ -79,11 +80,13 @@ public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpP public abstract void onClose(Channel channel); - protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future, HttpResponse response, final Channel channel) throws Exception { + protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future, HttpResponse response, final Channel channel) + throws Exception { io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); boolean redirectEnabled = request.isRedirectOverrideSet() ? request.isRedirectEnabled() : config.isRedirectEnabled(); - boolean isRedirectStatus = status.equals(MOVED_PERMANENTLY) || status.equals(FOUND) || status.equals(SEE_OTHER) || status.equals(TEMPORARY_REDIRECT); + boolean isRedirectStatus = status.equals(MOVED_PERMANENTLY) || status.equals(FOUND) || status.equals(SEE_OTHER) + || status.equals(TEMPORARY_REDIRECT); if (redirectEnabled && isRedirectStatus) { if (future.incrementAndGetCurrentRedirectCount() >= config.getMaxRedirects()) { @@ -150,7 +153,8 @@ public void call() throws Exception { // FIXME investigate this Channels.setDefaultAttribute(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? + // 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(); } @@ -164,13 +168,16 @@ public void call() throws Exception { return false; } - protected boolean handleResponseFiltersReplayRequestAndExit(Channel channel, NettyResponseFuture future, HttpResponseStatus status, HttpResponseHeaders responseHeaders) - throws IOException { + protected boolean handleResponseFiltersReplayRequestAndExit(// + Channel channel,// + NettyResponseFuture future,// + HttpResponseStatus status,// + HttpResponseHeaders responseHeaders) throws IOException { if (hasResponseFilters) { AsyncHandler handler = future.getAsyncHandler(); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()).responseStatus(status).responseHeaders(responseHeaders) - .build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) + .responseStatus(status).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { try { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 48ff1cdbdd..459643fe45 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -53,7 +53,10 @@ final class WebSocketProtocol extends Protocol { private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); - public WebSocketProtocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { + public WebSocketProtocol(Channels channels,// + AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + NettyRequestSender requestSender) { super(channels, config, nettyConfig, requestSender); } @@ -99,14 +102,14 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr status = new ResponseStatus(future.getURI(), response, config); final boolean statusReceived = h.onStatusReceived(status) == STATE.UPGRADE; - if (!statusReceived) { - try { - h.onCompleted(); - } finally { - future.done(); - } - return; - } + if (!statusReceived) { + try { + h.onCompleted(); + } finally { + future.done(); + } + return; + } final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { @@ -115,7 +118,8 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHttpRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHttpRequest().headers() + .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { channels.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 941ade5afe..7bfc6d8717 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -69,7 +69,8 @@ public void onFutureFailure(Channel channel, Throwable cause) { boolean canRetry = future.canRetry(); LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", channel, canRetry); - if (canRetry && cause != null + if (canRetry// + && cause != null// && (StackTraceInspector.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { LOGGER.debug("Retrying {} ", future.getNettyRequest()); @@ -81,7 +82,8 @@ public void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, channel); boolean printCause = cause != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString()); + String printedCause = printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString(); + ConnectException e = new ConnectException(printedCause); if (cause != null) { e.initCause(cause); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 027ec95716..77fda9c612 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -243,7 +243,8 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { } else if (request.getBodyGenerator() instanceof FileBodyGenerator) { FileBodyGenerator fileBodyGenerator = (FileBodyGenerator) request.getBodyGenerator(); - nettyBody = new NettyFileBody(fileBodyGenerator.getFile(), fileBodyGenerator.getRegionSeek(), fileBodyGenerator.getRegionLength(), nettyConfig); + 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()); @@ -309,7 +310,8 @@ public NettyRequest newNettyRequest(Request request, URI uri, boolean forceConne if (method != HttpMethod.CONNECT && webSocket) { httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); httpRequest.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - httpRequest.headers().set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); + httpRequest.headers().set(HttpHeaders.Names.ORIGIN, + "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); @@ -338,7 +340,8 @@ public NettyRequest newNettyRequest(Request request, URI uri, boolean forceConne // Add default user agent if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { - String userAgent = config.getUserAgent() != null ? config.getUserAgent() : AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class, config); + String userAgent = config.getUserAgent() != null ? config.getUserAgent() : AsyncHttpProviderUtils.constructUserAgent( + NettyAsyncHttpProvider.class, config); httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 026e362f7c..57e1210f65 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -66,7 +66,10 @@ public class NettyRequestSender { private final Channels channels; private final NettyRequestFactory requestFactory; - public NettyRequestSender(AtomicBoolean closed, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, Channels channels) { + public NettyRequestSender(AtomicBoolean closed,// + AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + Channels channels) { this.closed = closed; this.config = config; this.channels = channels; @@ -110,11 +113,13 @@ public boolean retry(NettyResponseFuture future, Channel channel) { return success; } - public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) throws IOException { + 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(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) + .ioException(e).build(); for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { try { fc = asyncFilter.filter(fc); @@ -150,8 +155,8 @@ private Channel getCachedChannel(NettyResponseFuture future, URI uri, Connect return channels.pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); } - private ListenableFuture sendRequestWithCachedChannel(Request request, URI uri, ProxyServer proxy, NettyResponseFuture future, AsyncHandler asyncHandler, - Channel channel) throws IOException { + private ListenableFuture sendRequestWithCachedChannel(Request request, URI uri, ProxyServer proxy, + NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); @@ -200,8 +205,14 @@ private ChannelFuture connect(Request request, URI uri, ProxyServer proxy, boole return bootstrap.connect(remoteAddress); } - private ListenableFuture sendRequestWithNewChannel(Request request, URI uri, ProxyServer proxy, boolean useProxy, NettyResponseFuture future, - AsyncHandler asyncHandler, boolean reclaimCache) throws IOException { + private ListenableFuture sendRequestWithNewChannel(// + Request request,// + URI uri,// + ProxyServer proxy,// + boolean useProxy,// + NettyResponseFuture future,// + AsyncHandler asyncHandler,// + boolean reclaimCache) throws IOException { boolean useSSl = isSecure(uri) && !useProxy; @@ -226,7 +237,8 @@ private ListenableFuture sendRequestWithNewChannel(Request request, URI u channelFuture.addListener(connectListener); - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest().getHttpRequest(), channelFuture.channel()); + LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest().getHttpRequest(), + channelFuture.channel()); if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { channels.registerChannel(channelFuture.channel()); @@ -237,10 +249,12 @@ private ListenableFuture sendRequestWithNewChannel(Request request, URI u return connectListener.future(); } - private NettyResponseFuture newNettyResponseFuture(URI uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { + private NettyResponseFuture newNettyResponseFuture(URI uri, Request request, AsyncHandler asyncHandler, + NettyRequest nettyRequest, ProxyServer proxyServer) { int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - NettyResponseFuture f = new NettyResponseFuture(uri,// + NettyResponseFuture f = new NettyResponseFuture(// + uri,// request,// asyncHandler,// nettyRequest,// @@ -256,8 +270,8 @@ private NettyResponseFuture newNettyResponseFuture(URI uri, Request reque return f; } - private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture originalFuture, URI uri, - ProxyServer proxy, boolean forceConnect) throws IOException { + private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, + NettyResponseFuture originalFuture, URI uri, ProxyServer proxy, boolean forceConnect) throws IOException { NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); @@ -274,7 +288,12 @@ private boolean isChannelValid(Channel channel) { return channel != null && channel.isOpen() && channel.isActive(); } - private ListenableFuture sendRequestThroughSslProxy(Request request, AsyncHandler asyncHandler, NettyResponseFuture future, boolean reclaimCache, URI uri, + private ListenableFuture sendRequestThroughSslProxy(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + URI uri,// ProxyServer proxyServer) throws IOException { // Using CONNECT depends on wither we can fetch a valid channel or not @@ -299,8 +318,15 @@ private ListenableFuture sendRequestThroughSslProxy(Request request, Asyn return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); } - private ListenableFuture sendRequestWithCertainForceConnect(Request request, AsyncHandler asyncHandler, NettyResponseFuture future, boolean reclaimCache, URI uri, - ProxyServer proxyServer, boolean useProxy, boolean forceConnect) throws IOException { + private ListenableFuture sendRequestWithCertainForceConnect(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + URI uri,// + ProxyServer proxyServer,// + boolean useProxy,// + boolean forceConnect) throws IOException { // 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 NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); @@ -313,7 +339,10 @@ private ListenableFuture sendRequestWithCertainForceConnect(Request reque return sendRequestWithNewChannel(request, uri, proxyServer, useProxy, newFuture, asyncHandler, reclaimCache); } - public ListenableFuture sendRequest(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture future, boolean reclaimCache) throws IOException { + public ListenableFuture sendRequest(final Request request,// + final AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache) throws IOException { if (closed.get()) { throw new IOException("Closed"); @@ -326,7 +355,8 @@ public ListenableFuture sendRequest(final Request request, final AsyncHan URI uri = config.isUseRawUrl() ? request.getRawURI() : request.getURI(); ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - boolean resultOfAConnect = future != null && future.getNettyRequest() != null && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; + boolean resultOfAConnect = future != null && future.getNettyRequest() != null + && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; boolean useProxy = proxyServer != null && !resultOfAConnect; if (useProxy && isSecure(uri)) { @@ -356,15 +386,16 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, nettyResponseFuture.getRequest()); TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { - Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, closed), requestTimeoutInMs); + Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, + closed), 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 = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, closed, - requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); + Timeout idleConnectionTimeout = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, + timeoutsHolder, closed, requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); @@ -394,7 +425,8 @@ public final void writeRequest(NettyResponseFuture future, Channel channe if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); } - channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); + channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener( + new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); } catch (Throwable cause) { // FIXME why not notify? LOGGER.debug(cause.getMessage(), cause); @@ -407,7 +439,8 @@ public final void writeRequest(NettyResponseFuture future, Channel channe } } - if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) && nettyRequest.getBody() != null) + if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) + && nettyRequest.getBody() != null) nettyRequest.getBody().write(channel, future, config); } catch (Throwable ioe) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java index 2f11214899..ad31a075bc 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java @@ -41,7 +41,8 @@ public class ProgressListener implements ChannelProgressiveFutureListener { private final long expectedTotal; private long lastProgress = 0L; - public ProgressListener(AsyncHttpClientConfig config, AsyncHandler asyncHandler, NettyResponseFuture future, boolean notifyHeaders, long expectedTotal) { + public ProgressListener(AsyncHttpClientConfig config, AsyncHandler asyncHandler, NettyResponseFuture future, + boolean notifyHeaders, long expectedTotal) { this.config = config; this.asyncHandler = asyncHandler; this.future = future; @@ -60,7 +61,8 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { } catch (RuntimeException ex) { LOGGER.debug(ex.getMessage(), ex); } - } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadCloseException(cause) || StackTraceInspector.abortOnWriteCloseException(cause)) { + } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadCloseException(cause) + || StackTraceInspector.abortOnWriteCloseException(cause)) { if (LOGGER.isDebugEnabled()) LOGGER.debug(cause.getMessage(), cause); @@ -90,7 +92,8 @@ public void operationComplete(ChannelProgressiveFuture 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, + * 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(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java index 26667946b9..2e8da2d845 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java @@ -23,9 +23,8 @@ 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. + * {@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); @@ -89,8 +88,8 @@ public long read(final ByteBuffer buffer) throws IOException { 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()); + for (int i = 0; i < size; i++) { + buffer.put(nextPart.buffer.get()); } buffer.put(END_PADDING); if (!nextPart.buffer.hasRemaining()) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java index 318c9a4a96..e848c21e39 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java @@ -68,16 +68,17 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien future.setStreamWasAlreadyConsumed(true); } - channel.write(new ChunkedStream(is), channel.newProgressivePromise()).addListener(new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { - public void operationComplete(ChannelProgressiveFuture cf) { - try { - is.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } - super.operationComplete(cf); - } - }); + channel.write(new ChunkedStream(is), channel.newProgressivePromise()).addListener( + new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { + public void operationComplete(ChannelProgressiveFuture cf) { + try { + is.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java index 24ce37a33a..99ef4bf1dd 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java @@ -29,8 +29,13 @@ public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { private final long idleConnectionTimeout; private final long requestTimeoutInstant; - public IdleConnectionTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, Channels channels, TimeoutsHolder timeoutsHolder, AtomicBoolean clientClosed, - long requestTimeout, long idleConnectionTimeout) { + public IdleConnectionTimeoutTimerTask(// + NettyResponseFuture nettyResponseFuture,// + Channels channels,// + TimeoutsHolder timeoutsHolder,// + AtomicBoolean clientClosed,// + long requestTimeout,// + long idleConnectionTimeout) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); this.idleConnectionTimeout = idleConnectionTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 9fdcd8bc46..65dcdb0387 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -26,7 +26,11 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { - public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, Channels channels, TimeoutsHolder timeoutsHolder, AtomicBoolean clientClosed) { + public RequestTimeoutTimerTask(// + NettyResponseFuture nettyResponseFuture,// + Channels channels,// + TimeoutsHolder timeoutsHolder,// + AtomicBoolean clientClosed) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); } @@ -41,7 +45,8 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - expire("Request timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms", millisTime() - nettyResponseFuture.getStart()); + expire("Request timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms", + millisTime() - nettyResponseFuture.getStart()); nettyResponseFuture.setRequestTimeoutReached(); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java index 715e1c773e..e599e5d871 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java @@ -34,7 +34,11 @@ public abstract class TimeoutTimerTask implements TimerTask { protected final TimeoutsHolder timeoutsHolder; protected final AtomicBoolean clientClosed; - public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, Channels channels, TimeoutsHolder timeoutsHolder, AtomicBoolean clientClosed) { + public TimeoutTimerTask(// + NettyResponseFuture nettyResponseFuture,// + Channels channels,// + TimeoutsHolder timeoutsHolder,// + AtomicBoolean clientClosed) { this.nettyResponseFuture = nettyResponseFuture; this.channels = channels; this.timeoutsHolder = timeoutsHolder; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java index 32ee9e6e22..aad1f2e5af 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java index 076273b217..31091bd605 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java index 7c57005112..d3e1f95451 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java @@ -42,7 +42,10 @@ public class NettyResponse extends ResponseBase { private final TimeConverter timeConverter; - public NettyResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts, TimeConverter timeConverter) { + public NettyResponse(HttpResponseStatus status,// + HttpResponseHeaders headers,// + List bodyParts,// + TimeConverter timeConverter) { super(status, headers, bodyParts); this.timeConverter = timeConverter; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java index 7268e2dbd4..8f08d5f08e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java @@ -37,7 +37,7 @@ public ResponseHeaders(URI uri, HttpHeaders responseHeaders) { this(uri, responseHeaders, null); } - public ResponseHeaders(URI uri,HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { + public ResponseHeaders(URI uri, HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { super(traillingHeaders != null); this.responseHeaders = responseHeaders; this.trailingHeaders = traillingHeaders; @@ -46,12 +46,12 @@ public ResponseHeaders(URI uri,HttpHeaders responseHeaders, HttpHeaders traillin private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (Map.Entry header: responseHeaders) { + for (Map.Entry header : responseHeaders) { h.add(header.getKey(), header.getValue()); } if (trailingHeaders != null) { - for (Map.Entry header: trailingHeaders) { + for (Map.Entry header : trailingHeaders) { h.add(header.getKey(), header.getValue()); } } @@ -61,7 +61,7 @@ private FluentCaseInsensitiveStringsMap computerHeaders() { /** * Return the HTTP header - * + * * @return an {@link org.asynchttpclient.FluentCaseInsensitiveStringsMap} */ @Override diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java index 29e23e84e6..43d3f8a0e1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java @@ -31,14 +31,14 @@ * A class that represent the HTTP response' status line (code + text) */ public class ResponseStatus extends HttpResponseStatus { - + private final HttpResponse response; public ResponseStatus(URI uri, HttpResponse response, AsyncHttpClientConfig config) { super(uri, config); this.response = response; } - + @Override public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { return new NettyResponse(this, headers, bodyParts, config.getTimeConverter()); @@ -46,7 +46,7 @@ public Response prepareResponse(HttpResponseHeaders headers, ListBruno de Carvalho */ public class CleanupChannelGroup extends DefaultChannelGroup { - // internal vars -------------------------------------------------------------------------------------------------- private final AtomicBoolean closed = new AtomicBoolean(false); @@ -69,10 +68,11 @@ public ChannelGroupFuture close() { // First time close() is called. return super.close(); } else { - // FIXME DefaultChannelGroupFuture is package protected -// Collection futures = new ArrayList(); -// logger.debug("CleanupChannelGroup already closed"); -// return new DefaultChannelGroupFuture(ChannelGroup.class.cast(this), futures, GlobalEventExecutor.INSTANCE); + // FIXME DefaultChannelGroupFuture is package protected + // Collection futures = new ArrayList(); + // logger.debug("CleanupChannelGroup already closed"); + // return new DefaultChannelGroupFuture(ChannelGroup.class.cast(this), futures, + // GlobalEventExecutor.INSTANCE); throw new UnsupportedOperationException("CleanupChannelGroup already closed"); } } finally { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java index 66d3854858..57b99ae2a5 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java @@ -17,16 +17,16 @@ import java.net.URI; import java.util.List; -public class HttpUtil { - - private HttpUtil() { - } +public final class HttpUtil { public static final String HTTPS = "https"; public static final String HTTP = "http"; 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"); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java index 40134e7924..4097ab31d6 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java @@ -20,6 +20,7 @@ import java.security.NoSuchAlgorithmException; public final class WebSocketUtil { + public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; public static String getKey() { diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java index 288f9a32d2..eeb0008d6f 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java @@ -30,7 +30,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { config.addProperty("TCP_NODELAY", true); return config; } - + @Override protected String acceptEncodingHeader() { return "gzip,deflate"; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java index 37d0d63e0a..15e2a1f7bb 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderPipelineTest.java @@ -50,7 +50,8 @@ public void initChannel(Channel ch) throws Exception { ch.pipeline().addBefore("inflater", "copyEncodingHeader", new CopyEncodingHandler()); } }); - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setAsyncHttpClientProviderConfig(nettyConfig).build()); + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true) + .setAsyncHttpClientProviderConfig(nettyConfig).build()); try { final CountDownLatch l = new CountDownLatch(1); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyBasicAuthTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyBasicAuthTest.java index 69dfb34b78..589cfd1e6f 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyBasicAuthTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyBasicAuthTest.java @@ -25,6 +25,6 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override public String getProviderClass() { - return NettyAsyncHttpProvider.class.getName(); + return NettyAsyncHttpProvider.class.getName(); } } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java index 198f954bce..156aeb9699 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java @@ -61,8 +61,8 @@ public void destroy() { NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); providerConfig.setChannelPool(cp); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setAsyncHttpClientProviderConfig(providerConfig).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig) + .build()); try { Exception exception = null; try { @@ -105,8 +105,8 @@ public void destroy() { NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); providerConfig.setChannelPool(cp); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setAsyncHttpClientProviderConfig(providerConfig).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig) + .build()); try { Exception exception = null; try { diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProxyTunnellingTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProxyTunnellingTest.java index 396964f8cd..2d47058543 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProxyTunnellingTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProxyTunnellingTest.java @@ -23,6 +23,6 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { } public String getProviderClass() { - return NettyAsyncHttpProvider.class.getName(); + return NettyAsyncHttpProvider.class.getName(); } } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java index 8618a4a6ce..82e39012db 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java @@ -54,7 +54,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(); @@ -80,11 +81,11 @@ public void run() { 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()); + int samples = 10; - + try { final CountDownLatch latch = new CountDownLatch(samples); final List tooManyConnections = Collections.synchronizedList(new ArrayList(2)); @@ -97,23 +98,24 @@ public void run() { 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 { - return response; - } - - @Override - public void onThrowable(Throwable t) { - logger.error("onThrowable got an error", t); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - } - requestThrottle.release(); - } - }); + responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(SLEEPTIME_MS / 2) + .execute(new AsyncCompletionHandler() { + + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } + + @Override + public void onThrowable(Throwable t) { + logger.error("onThrowable got an error", t); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + requestThrottle.release(); + } + }); } catch (Exception e) { tooManyConnections.add(e); } @@ -135,7 +137,7 @@ public void onThrowable(Throwable t) { fail("failed to wait for requests to complete"); } - for (Exception e: tooManyConnections) + for (Exception e : tooManyConnections) logger.error("Exception while calling execute", e); assertTrue(tooManyConnections.isEmpty(), "Should not have any connection errors where too many connections have been attempted"); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRetryRequestTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRetryRequestTest.java index d00acde3c2..8ea77a62f2 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRetryRequestTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRetryRequestTest.java @@ -20,7 +20,7 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.async.RetryRequestTest; -public class NettyRetryRequestTest extends RetryRequestTest{ +public class NettyRetryRequestTest extends RetryRequestTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return NettyProviderUtil.nettyProvider(config); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettySimpleAsyncHttpClientTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettySimpleAsyncHttpClientTest.java index 2f7c9b4e23..0b117c9ee6 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettySimpleAsyncHttpClientTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettySimpleAsyncHttpClientTest.java @@ -20,6 +20,7 @@ public class NettySimpleAsyncHttpClientTest extends SimpleAsyncHttpClientTest { /** * Not Used with {@link org.asynchttpclient.SimpleAsyncHttpClient} + * * @param config * @return */ From 04be5a6946aa7a50b643f1a31c466a9b379c9100 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 14:31:10 +0100 Subject: [PATCH 0013/2070] Advertise contribution rules --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index a93ceab8b0..ebd1fb6b13 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,8 @@ Future f = c.prepareGet("http://www.ning.com/").execute(new AsyncHandler String bodyResponse = f.get(); ``` +## Configuration + Finally, you can also configure the AsyncHttpClient via its AsyncHttpClientConfig object: ```java @@ -141,6 +143,8 @@ AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder() AsyncHttpClient c = new AsyncHttpClient(cf); ``` +## WebSocket + Async Http Client also support WebSocket by simply doing: ```java @@ -175,6 +179,8 @@ AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); ``` +## User Group + Keep up to date on the library development by joining the Asynchronous HTTP Client discussion group [Google Group](http://groups.google.com/group/asynchttpclient) @@ -182,3 +188,20 @@ Keep up to date on the library development by joining the Asynchronous HTTP Clie or follow us on [Twitter](http://twitter.com/jfarcand) [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/6433679063b2351599c6ca44a08246a2 "githalytics.com")](http://githalytics.com/AsyncHttpClient/async-http-client) + +## Contributing + +Of course, Pull Requests are welcome. + +Here a the few rules we'd like you to respect if you do so: + +* Only edit the code related to the suggested change, so DON'T automatically format the classes you've edited. +* Respect the formatting rules: + * Ident with 4 spaces + * Use a 140 chars line max length + * Don't use * imports + * Stick to the org, com, javax, java imports order +* Your PR can contain multiple commits when submitting, but once it's been reviewed, we'll ask you to squash the them into a single once +* Regarding licensing: + * You must be the original author of the code you suggest. + * If not, you have to prove that the original code was published under Apache License 2 and properly mention original copyrights. From 580ba5099ce6f18305d80b96a0c243f45ef47070 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Feb 2014 21:24:56 +0100 Subject: [PATCH 0014/2070] Format + organize imports on Grizzly and extras --- .../RateLimitedThrottleRequestFilter.java | 141 +++++++-------- .../extra/AsyncHttpDeferredObject.java | 62 +++---- .../extra/ContentWriteProgress.java | 44 +++-- .../extra/HttpResponseBodyPartProgress.java | 24 +-- .../providers/grizzly/ConnectionManager.java | 141 ++++++--------- .../providers/grizzly/ConnectionPool.java | 41 ++--- .../providers/grizzly/EventHandler.java | 171 ++++++------------ .../grizzly/FeedableBodyGenerator.java | 115 +++--------- .../grizzly/GrizzlyAsyncHttpProvider.java | 156 +++++----------- .../GrizzlyAsyncHttpProviderConfig.java | 33 ++-- .../providers/grizzly/GrizzlyResponse.java | 58 +----- .../grizzly/GrizzlyResponseBodyPart.java | 23 +-- .../grizzly/GrizzlyResponseFuture.java | 43 +---- .../grizzly/GrizzlyResponseHeaders.java | 7 - .../grizzly/GrizzlyResponseStatus.java | 33 +--- .../providers/grizzly/HttpTxContext.java | 49 ++--- .../grizzly/ProxyAwareConnectorHandler.java | 31 +--- .../providers/grizzly/RequestInfoHolder.java | 11 +- .../grizzly/TransportCustomizer.java | 4 +- .../providers/grizzly/Utils.java | 31 ++-- .../bodyhandler/BodyGeneratorBodyHandler.java | 12 +- .../grizzly/bodyhandler/BodyHandler.java | 5 +- .../bodyhandler/BodyHandlerFactory.java | 16 +- .../bodyhandler/ByteArrayBodyHandler.java | 14 +- .../grizzly/bodyhandler/ExpectHandler.java | 7 +- .../grizzly/bodyhandler/FileBodyHandler.java | 39 ++-- .../grizzly/bodyhandler/NoBodyHandler.java | 12 +- .../bodyhandler/ParamsBodyHandler.java | 13 +- .../grizzly/bodyhandler/PartsBodyHandler.java | 22 +-- .../bodyhandler/StreamDataBodyHandler.java | 11 +- .../bodyhandler/StringBodyHandler.java | 10 +- .../filters/AsyncHttpClientEventFilter.java | 10 +- .../filters/AsyncHttpClientFilter.java | 23 +-- .../filters/AsyncSpdyClientEventFilter.java | 10 +- .../grizzly/filters/ClientEncodingFilter.java | 12 +- .../grizzly/filters/ProxyFilter.java | 35 ++-- .../grizzly/filters/SwitchingSSLFilter.java | 81 ++++----- .../grizzly/filters/TunnelFilter.java | 17 +- .../grizzly/filters/events/ContinueEvent.java | 9 - .../filters/events/SSLSwitchingEvent.java | 8 - .../filters/events/TunnelRequestEvent.java | 10 +- .../statushandler/AuthorizationHandler.java | 59 ++---- .../ProxyAuthorizationHandler.java | 135 ++++---------- .../statushandler/RedirectHandler.java | 51 ++---- .../grizzly/statushandler/StatusHandler.java | 8 +- .../AHCWebSocketListenerAdapter.java | 12 +- .../websocket/GrizzlyWebSocketAdapter.java | 8 +- .../GrizzlyAsyncProviderBasicTest.java | 1 - .../GrizzlyAsyncStreamHandlerTest.java | 1 - .../GrizzlyAsyncStreamLifecycleTest.java | 1 - .../grizzly/GrizzlyAuthTimeoutTest.java | 2 - .../grizzly/GrizzlyBasicAuthTest.java | 1 - .../grizzly/GrizzlyBodyChunkTest.java | 1 - .../GrizzlyByteBufferCapacityTest.java | 2 +- .../grizzly/GrizzlyChunkingTest.java | 1 - .../grizzly/GrizzlyComplexClientTest.java | 1 - .../grizzly/GrizzlyConnectionPoolTest.java | 5 +- .../grizzly/GrizzlyDigestAuthTest.java | 1 - .../grizzly/GrizzlyEmptyBodyTest.java | 1 - .../grizzly/GrizzlyErrorResponseTest.java | 1 - .../grizzly/GrizzlyExpectContinue100Test.java | 3 +- .../providers/grizzly/GrizzlyFilterTest.java | 1 - .../grizzly/GrizzlyFollowingThreadTest.java | 1 - .../providers/grizzly/GrizzlyHead302Test.java | 1 - .../grizzly/GrizzlyHostnameVerifierTest.java | 1 - .../GrizzlyHttpToHttpsRedirectTest.java | 1 - .../grizzly/GrizzlyIdleStateHandlerTest.java | 1 - .../grizzly/GrizzlyInputStreamTest.java | 1 - .../grizzly/GrizzlyListenableFutureTest.java | 1 - .../GrizzlyMaxConnectionsInThreadsTest.java | 2 +- .../grizzly/GrizzlyMultipleHeaderTest.java | 1 - .../grizzly/GrizzlyNoNullResponseTest.java | 1 - .../GrizzlyNonAsciiContentLengthTest.java | 1 - .../grizzly/GrizzlyParamEncodingTest.java | 1 - .../GrizzlyPerRequestRelative302Test.java | 1 - .../grizzly/GrizzlyPerRequestTimeoutTest.java | 1 - .../grizzly/GrizzlyPostWithQSTest.java | 1 - .../providers/grizzly/GrizzlyProxyTest.java | 1 - .../grizzly/GrizzlyProxyTunnelingTest.java | 2 +- .../grizzly/GrizzlyPutLargeFileTest.java | 1 - .../grizzly/GrizzlyQueryParametersTest.java | 3 +- .../grizzly/GrizzlyRelative302Test.java | 1 - .../grizzly/GrizzlyRemoteSiteTest.java | 1 - .../grizzly/GrizzlyRetryRequestTest.java | 1 - .../grizzly/GrizzlyTransferListenerTest.java | 1 - .../GrizzlyUnexpectingTimeoutTest.java | 3 +- 86 files changed, 591 insertions(+), 1329 deletions(-) diff --git a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java b/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java index c3c24a4b31..d6ddb69a68 100644 --- a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java +++ b/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java @@ -21,75 +21,72 @@ * it will only spend another 500 ms waiting for the rate limiter. */ public class RateLimitedThrottleRequestFilter implements RequestFilter { - private final static Logger logger = LoggerFactory.getLogger(RateLimitedThrottleRequestFilter.class); - private final Semaphore available; - private final int maxWaitMs; - private final RateLimiter rateLimiter; - - public RateLimitedThrottleRequestFilter(int maxConnections, double rateLimitPerSecond) { - this(maxConnections, rateLimitPerSecond, Integer.MAX_VALUE); - } - - public RateLimitedThrottleRequestFilter(int maxConnections, double rateLimitPerSecond, int maxWaitMs) { - this.maxWaitMs = maxWaitMs; - this.rateLimiter = RateLimiter.create(rateLimitPerSecond); - available = new Semaphore(maxConnections, true); - } - - /** - * {@inheritDoc} - */ - @Override - public FilterContext filter(FilterContext ctx) throws FilterException { - try { - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status {}", available.availablePermits()); - } - - long startOfWait = System.currentTimeMillis(); - attemptConcurrencyPermitAcquistion(ctx); - - attemptRateLimitedPermitAcquistion(ctx, startOfWait); - } catch (InterruptedException e) { - throw new FilterException(String.format("Interrupted Request %s with AsyncHandler %s", ctx.getRequest(), - ctx.getAsyncHandler())); - } - - return new FilterContext.FilterContextBuilder(ctx).asyncHandler( - new AsyncHandlerWrapper(ctx.getAsyncHandler(), available)).build(); - } - - private void attemptRateLimitedPermitAcquistion(FilterContext ctx, long startOfWait) throws FilterException { - long wait = getMillisRemainingInMaxWait(startOfWait); - - if (!rateLimiter.tryAcquire(wait, TimeUnit.MILLISECONDS)) { - throw new FilterException(String.format( - "Wait for rate limit exceeded during processing Request %s with AsyncHandler %s", ctx.getRequest(), - ctx.getAsyncHandler())); - } - } - - private void attemptConcurrencyPermitAcquistion(FilterContext ctx) throws InterruptedException, - FilterException { - if (!available.tryAcquire(maxWaitMs, TimeUnit.MILLISECONDS)) { - throw new FilterException(String.format("No slot available for processing Request %s with AsyncHandler %s", - ctx.getRequest(), ctx.getAsyncHandler())); - } - } - - private long getMillisRemainingInMaxWait(long startOfWait) { - int MINUTE_IN_MILLIS = 60000; - long durationLeft = maxWaitMs - (System.currentTimeMillis() - startOfWait); - long nonNegativeDuration = Math.max(durationLeft, 0); - - // have to reduce the duration because there is a boundary case inside the Guava - // rate limiter where if the duration to wait is near Long.MAX_VALUE, the rate - // limiter's internal calculations can exceed Long.MAX_VALUE resulting in a - // negative number which causes the tryAcquire() method to fail unexpectedly - if (Long.MAX_VALUE - nonNegativeDuration < MINUTE_IN_MILLIS) { - return nonNegativeDuration - MINUTE_IN_MILLIS; - } - - return nonNegativeDuration; - } -} \ No newline at end of file + private final static Logger logger = LoggerFactory.getLogger(RateLimitedThrottleRequestFilter.class); + private final Semaphore available; + private final int maxWaitMs; + private final RateLimiter rateLimiter; + + public RateLimitedThrottleRequestFilter(int maxConnections, double rateLimitPerSecond) { + this(maxConnections, rateLimitPerSecond, Integer.MAX_VALUE); + } + + public RateLimitedThrottleRequestFilter(int maxConnections, double rateLimitPerSecond, int maxWaitMs) { + this.maxWaitMs = maxWaitMs; + this.rateLimiter = RateLimiter.create(rateLimitPerSecond); + available = new Semaphore(maxConnections, true); + } + + /** + * {@inheritDoc} + */ + @Override + public FilterContext filter(FilterContext ctx) throws FilterException { + try { + if (logger.isDebugEnabled()) { + logger.debug("Current Throttling Status {}", available.availablePermits()); + } + + long startOfWait = System.currentTimeMillis(); + attemptConcurrencyPermitAcquistion(ctx); + + attemptRateLimitedPermitAcquistion(ctx, startOfWait); + } catch (InterruptedException e) { + throw new FilterException(String.format("Interrupted Request %s with AsyncHandler %s", ctx.getRequest(), ctx.getAsyncHandler())); + } + + return new FilterContext.FilterContextBuilder(ctx).asyncHandler(new AsyncHandlerWrapper(ctx.getAsyncHandler(), available)) + .build(); + } + + private void attemptRateLimitedPermitAcquistion(FilterContext ctx, long startOfWait) throws FilterException { + long wait = getMillisRemainingInMaxWait(startOfWait); + + if (!rateLimiter.tryAcquire(wait, TimeUnit.MILLISECONDS)) { + throw new FilterException(String.format("Wait for rate limit exceeded during processing Request %s with AsyncHandler %s", + ctx.getRequest(), ctx.getAsyncHandler())); + } + } + + private void attemptConcurrencyPermitAcquistion(FilterContext ctx) throws InterruptedException, FilterException { + if (!available.tryAcquire(maxWaitMs, TimeUnit.MILLISECONDS)) { + throw new FilterException(String.format("No slot available for processing Request %s with AsyncHandler %s", ctx.getRequest(), + ctx.getAsyncHandler())); + } + } + + private long getMillisRemainingInMaxWait(long startOfWait) { + int MINUTE_IN_MILLIS = 60000; + long durationLeft = maxWaitMs - (System.currentTimeMillis() - startOfWait); + long nonNegativeDuration = Math.max(durationLeft, 0); + + // have to reduce the duration because there is a boundary case inside the Guava + // rate limiter where if the duration to wait is near Long.MAX_VALUE, the rate + // limiter's internal calculations can exceed Long.MAX_VALUE resulting in a + // negative number which causes the tryAcquire() method to fail unexpectedly + if (Long.MAX_VALUE - nonNegativeDuration < MINUTE_IN_MILLIS) { + return nonNegativeDuration - MINUTE_IN_MILLIS; + } + + return nonNegativeDuration; + } +} diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java index d0b928cb1d..5763048d0a 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java @@ -26,36 +26,34 @@ import java.io.IOException; public class AsyncHttpDeferredObject extends DeferredObject { - public AsyncHttpDeferredObject(BoundRequestBuilder builder) throws IOException { - builder.execute(new AsyncCompletionHandler() { - @Override - public Void onCompleted(Response response) throws Exception { - AsyncHttpDeferredObject.this.resolve(response); - return null; - } - - @Override - public void onThrowable(Throwable t) { - AsyncHttpDeferredObject.this.reject(t); - } - - @Override - public AsyncHandler.STATE onContentWriteProgress( - long amount, long current, long total) { - AsyncHttpDeferredObject.this.notify(new ContentWriteProgress(amount, current, total)); - return super.onContentWriteProgress(amount, current, total); - } - - @Override - public AsyncHandler.STATE onBodyPartReceived( - HttpResponseBodyPart content) throws Exception { - AsyncHttpDeferredObject.this.notify(new HttpResponseBodyPartProgress(content)); - return super.onBodyPartReceived(content); - } - }); - } - - public static Promise promise(final BoundRequestBuilder builder) throws IOException { - return new AsyncHttpDeferredObject(builder).promise(); - } + public AsyncHttpDeferredObject(BoundRequestBuilder builder) throws IOException { + builder.execute(new AsyncCompletionHandler() { + @Override + public Void onCompleted(Response response) throws Exception { + AsyncHttpDeferredObject.this.resolve(response); + return null; + } + + @Override + public void onThrowable(Throwable t) { + AsyncHttpDeferredObject.this.reject(t); + } + + @Override + public AsyncHandler.STATE onContentWriteProgress(long amount, long current, long total) { + AsyncHttpDeferredObject.this.notify(new ContentWriteProgress(amount, current, total)); + return super.onContentWriteProgress(amount, current, total); + } + + @Override + public AsyncHandler.STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + AsyncHttpDeferredObject.this.notify(new HttpResponseBodyPartProgress(content)); + return super.onBodyPartReceived(content); + } + }); + } + + public static Promise promise(final BoundRequestBuilder builder) throws IOException { + return new AsyncHttpDeferredObject(builder).promise(); + } } diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java index d340a89c69..0f3b5b5ddc 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java @@ -16,32 +16,30 @@ package org.asynchttpclient.extra; public class ContentWriteProgress implements HttpProgress { - private final long amount; - private final long current; - private final long total; + private final long amount; + private final long current; + private final long total; - public ContentWriteProgress(long amount, long current, long total) { - this.amount = amount; - this.current = current; - this.total = total; - } + public ContentWriteProgress(long amount, long current, long total) { + this.amount = amount; + this.current = current; + this.total = total; + } - public long getAmount() { - return amount; - } + public long getAmount() { + return amount; + } - public long getCurrent() { - return current; - } + public long getCurrent() { + return current; + } - public long getTotal() { - return total; - } + public long getTotal() { + return total; + } - @Override - public String toString() { - return "ContentWriteProgress [amount=" + amount + ", current=" - + current + ", total=" + total + "]"; - } - + @Override + public String toString() { + return "ContentWriteProgress [amount=" + amount + ", current=" + current + ", total=" + total + "]"; + } } diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java index 16c84e9e1b..362d1fb1a8 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java @@ -18,18 +18,18 @@ import org.asynchttpclient.HttpResponseBodyPart; public class HttpResponseBodyPartProgress implements HttpProgress { - private final HttpResponseBodyPart part; + private final HttpResponseBodyPart part; - public HttpResponseBodyPartProgress(HttpResponseBodyPart part) { - this.part = part; - } + public HttpResponseBodyPartProgress(HttpResponseBodyPart part) { + this.part = part; + } - public HttpResponseBodyPart getPart() { - return part; - } - - @Override - public String toString() { - return "HttpResponseBodyPartProgress [part=" + part + "]"; - } + public HttpResponseBodyPart getPart() { + return part; + } + + @Override + public String toString() { + return "HttpResponseBodyPartProgress [part=" + part + "]"; + } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index 7cc219545b..41984d449f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -51,26 +51,22 @@ public class ConnectionManager { - private static final Attribute DO_NOT_CACHE = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(ConnectionManager.class.getName()); + private static final Attribute DO_NOT_CACHE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(ConnectionManager.class + .getName()); private final ConnectionPool connectionPool; private final GrizzlyAsyncHttpProvider provider; private final boolean canDestroyPool; - private final Map> endpointKeyMap = new HashMap>(); + private final Map> endpointKeyMap = new HashMap>(); private final FilterChainBuilder secureBuilder; private final FilterChainBuilder nonSecureBuilder; private final boolean asyncConnect; - // ------------------------------------------------------------ Constructors - - @SuppressWarnings("unchecked") - ConnectionManager(final GrizzlyAsyncHttpProvider provider, - final ConnectionPool connectionPool, - final FilterChainBuilder secureBuilder, - final FilterChainBuilder nonSecureBuilder) { - + ConnectionManager(final GrizzlyAsyncHttpProvider provider,// + final ConnectionPool connectionPool,// + final FilterChainBuilder secureBuilder,// + final FilterChainBuilder nonSecureBuilder) { this.provider = provider; final AsyncHttpClientConfig config = provider.getClientConfig(); @@ -78,33 +74,28 @@ public class ConnectionManager { this.connectionPool = connectionPool; canDestroyPool = false; } else { - this.connectionPool = - new ConnectionPool(config.getMaxConnectionPerHost(), - config.getMaxTotalConnections(), - null, - config.getConnectionTimeoutInMs(), - config.getIdleConnectionInPoolTimeoutInMs(), - 2000); + this.connectionPool = new ConnectionPool(config.getMaxConnectionPerHost(),// + config.getMaxTotalConnections(),// + null,// + config.getConnectionTimeoutInMs(),// + config.getIdleConnectionInPoolTimeoutInMs(),// + 2000); canDestroyPool = true; } this.secureBuilder = secureBuilder; this.nonSecureBuilder = nonSecureBuilder; - AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); - asyncConnect = providerConfig instanceof GrizzlyAsyncHttpProviderConfig? GrizzlyAsyncHttpProviderConfig.class.cast(providerConfig).isAsyncConnectMode() : false; + AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); + asyncConnect = providerConfig instanceof GrizzlyAsyncHttpProviderConfig ? GrizzlyAsyncHttpProviderConfig.class.cast(providerConfig) + .isAsyncConnectMode() : false; } - // ---------------------------------------------------------- Public Methods - - public void doTrackedConnection(final Request request, - final GrizzlyResponseFuture requestFuture, - final CompletionHandler connectHandler) - throws IOException { - final EndpointKey key = - getEndPointKey(request, requestFuture.getProxyServer()); - CompletionHandler handler = - wrapHandler(request, getVerifier(), connectHandler); + public void doTrackedConnection(final Request request,// + final GrizzlyResponseFuture requestFuture,// + final CompletionHandler connectHandler) throws IOException { + final EndpointKey key = getEndPointKey(request, requestFuture.getProxyServer()); + CompletionHandler handler = wrapHandler(request, getVerifier(), connectHandler); if (asyncConnect) { connectionPool.take(key, handler); } else { @@ -133,9 +124,8 @@ public void doTrackedConnection(final Request request, } } - public Connection obtainConnection(final Request request, - final GrizzlyResponseFuture requestFuture) - throws ExecutionException, InterruptedException, TimeoutException { + public Connection obtainConnection(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, + InterruptedException, TimeoutException { final Connection c = obtainConnection0(request, requestFuture); markConnectionAsDoNotCache(c); @@ -145,9 +135,8 @@ public Connection obtainConnection(final Request request, // --------------------------------------------------Package Private Methods - static CompletionHandler wrapHandler(final Request request, - final HostnameVerifier verifier, - final CompletionHandler delegate) { + static CompletionHandler wrapHandler(final Request request, final HostnameVerifier verifier, + final CompletionHandler delegate) { final URI uri = request.getURI(); if (Utils.isSecure(uri) && verifier != null) { return new EmptyCompletionHandler() { @@ -182,54 +171,38 @@ public void updated(Connection result) { return delegate; } - static void markConnectionAsDoNotCache(final Connection c) { DO_NOT_CACHE.set(c, Boolean.TRUE); } static boolean isConnectionCacheable(final Connection c) { - final Boolean canCache = DO_NOT_CACHE.get(c); + final Boolean canCache = DO_NOT_CACHE.get(c); return ((canCache != null) ? canCache : false); } - // --------------------------------------------------------- Private Methods private HostnameVerifier getVerifier() { return provider.getClientConfig().getHostnameVerifier(); } - private EndpointKey getEndPointKey(final Request request, - final ProxyServer proxyServer) { + private EndpointKey getEndPointKey(final Request request, final ProxyServer proxyServer) { final String stringKey = getPoolKey(request, proxyServer); EndpointKey key = endpointKeyMap.get(stringKey); if (key == null) { synchronized (endpointKeyMap) { key = endpointKeyMap.get(stringKey); if (key == null) { - SocketAddress address = - getRemoteAddress(request, proxyServer); + SocketAddress address = getRemoteAddress(request, proxyServer); InetAddress localAddress = request.getLocalAddress(); InetSocketAddress localSocketAddress = null; if (localAddress != null) { localSocketAddress = new InetSocketAddress(localAddress.getHostName(), 0); } - ProxyAwareConnectorHandler handler = - ProxyAwareConnectorHandler - .builder(provider.clientTransport) - .nonSecureFilterChainTemplate( - nonSecureBuilder) - .secureFilterChainTemplate(secureBuilder) - .asyncHttpClientConfig( - provider.getClientConfig()) - .uri(request.getURI()) - .proxyServer(proxyServer) - .build(); - EndpointKey localKey = - new EndpointKey(stringKey, - address, - localSocketAddress, - handler); + ProxyAwareConnectorHandler handler = ProxyAwareConnectorHandler.builder(provider.clientTransport) + .nonSecureFilterChainTemplate(nonSecureBuilder).secureFilterChainTemplate(secureBuilder) + .asyncHttpClientConfig(provider.getClientConfig()).uri(request.getURI()).proxyServer(proxyServer).build(); + EndpointKey localKey = new EndpointKey(stringKey, address, localSocketAddress, handler); endpointKeyMap.put(stringKey, localKey); key = localKey; } @@ -238,15 +211,10 @@ private EndpointKey getEndPointKey(final Request request, return key; } - private SocketAddress getRemoteAddress(final Request request, - final ProxyServer proxyServer) { + private SocketAddress getRemoteAddress(final Request request, final ProxyServer proxyServer) { final URI requestUri = request.getURI(); - final String host = ((proxyServer != null) - ? proxyServer.getHost() - : requestUri.getHost()); - final int port = ((proxyServer != null) - ? proxyServer.getPort() - : requestUri.getPort()); + final String host = ((proxyServer != null) ? proxyServer.getHost() : requestUri.getHost()); + final int port = ((proxyServer != null) ? proxyServer.getPort() : requestUri.getPort()); return new InetSocketAddress(host, getPort(request.getURI(), port)); } @@ -259,16 +227,14 @@ private static int getPort(final URI uri, final int p) { } else if ("https".equals(protocol) || "wss".equals(protocol)) { port = 443; } else { - throw new IllegalArgumentException( - "Unknown protocol: " + protocol); + throw new IllegalArgumentException("Unknown protocol: " + protocol); } } return port; } - private Connection obtainConnection0(final Request request, - final GrizzlyResponseFuture requestFuture) - throws ExecutionException, InterruptedException, TimeoutException { + private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, + InterruptedException, TimeoutException { final int cTimeout = provider.getClientConfig().getConnectionTimeoutInMs(); final FutureImpl future = Futures.createSafeFuture(); @@ -276,14 +242,13 @@ private Connection obtainConnection0(final Request request, createConnectionCompletionHandler(request, requestFuture, null)); final ProxyServer proxyServer = requestFuture.getProxyServer(); final SocketAddress address = getRemoteAddress(request, proxyServer); - ProxyAwareConnectorHandler handler = ProxyAwareConnectorHandler - .builder(provider.clientTransport) - .nonSecureFilterChainTemplate(nonSecureBuilder) - .secureFilterChainTemplate(secureBuilder) - .asyncHttpClientConfig(provider.getClientConfig()) - .uri(request.getURI()) - .proxyServer(proxyServer) - .build(); + ProxyAwareConnectorHandler handler = ProxyAwareConnectorHandler.builder(provider.clientTransport) + .nonSecureFilterChainTemplate(nonSecureBuilder)// + .secureFilterChainTemplate(secureBuilder)// + .asyncHttpClientConfig(provider.getClientConfig())// + .uri(request.getURI())// + .proxyServer(proxyServer)// + .build(); if (cTimeout > 0) { handler.connect(address, ch); return future.get(cTimeout, MILLISECONDS); @@ -294,29 +259,26 @@ private Connection obtainConnection0(final Request request, } boolean returnConnection(final Connection c) { - final boolean result = (DO_NOT_CACHE.get(c) == null - && connectionPool.release(c)); + final boolean result = (DO_NOT_CACHE.get(c) == null && connectionPool.release(c)); if (result) { if (provider.getResolver() != null) { provider.getResolver().setTimeoutMillis(c, IdleTimeoutFilter.FOREVER); } } return result; - } - void destroy() { - if (canDestroyPool) { connectionPool.close(); } - } - CompletionHandler createConnectionCompletionHandler(final Request request, - final GrizzlyResponseFuture future, - final CompletionHandler wrappedHandler) { + CompletionHandler createConnectionCompletionHandler(// + final Request request,// + final GrizzlyResponseFuture future,// + final CompletionHandler wrappedHandler) { + return new CompletionHandler() { public void cancelled() { if (wrappedHandler != null) { @@ -355,5 +317,4 @@ private static String getPoolKey(final Request request, ProxyServer proxyServer) final ConnectionPoolKeyStrategy keyStrategy = request.getConnectionPoolKeyStrategy(); return keyStrategy.getKey(request.getURI(), proxyServer); } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionPool.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionPool.java index 0aec5b6a19..11197930d7 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionPool.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionPool.java @@ -31,32 +31,33 @@ * @since 2.0 * @author The Grizzly Team */ -public class ConnectionPool extends MultiEndpointPool{ +public class ConnectionPool extends MultiEndpointPool { private final Object lock = new Object(); // ------------------------------------------------------------ Constructors - - public ConnectionPool(final int maxConnectionsPerEndpoint, - final int maxConnectionsTotal, - final DelayedExecutor delayedExecutor, - final long connectTimeoutMillis, - final long keepAliveTimeoutMillis, - final long keepAliveCheckIntervalMillis) { - super(null, maxConnectionsPerEndpoint, - maxConnectionsTotal, delayedExecutor, connectTimeoutMillis, - keepAliveTimeoutMillis, keepAliveCheckIntervalMillis, -1, -1); + public ConnectionPool(final int maxConnectionsPerEndpoint,// + final int maxConnectionsTotal,// + final DelayedExecutor delayedExecutor,// + final long connectTimeoutMillis,// + final long keepAliveTimeoutMillis,// + final long keepAliveCheckIntervalMillis) { + super(null,// + maxConnectionsPerEndpoint,// + maxConnectionsTotal,// + delayedExecutor,// + connectTimeoutMillis,// + keepAliveTimeoutMillis,// + keepAliveCheckIntervalMillis,// + -1,// + -1); } - // ------------------------------------------ Methods from MultiEndpointPool - - protected SingleEndpointPool obtainSingleEndpointPool( - final EndpointKey endpointKey) throws IOException { - SingleEndpointPool sePool = - endpointToPoolMap.get(endpointKey); + protected SingleEndpointPool obtainSingleEndpointPool(final EndpointKey endpointKey) throws IOException { + SingleEndpointPool sePool = endpointToPoolMap.get(endpointKey); if (sePool == null) { synchronized (poolSync) { checkNotClosed(); @@ -92,8 +93,7 @@ public void completed(Connection result) { } @Override - public void take(final EndpointKey endpointKey, - final CompletionHandler completionHandler) { + public void take(final EndpointKey endpointKey, final CompletionHandler completionHandler) { synchronized (lock) { if (completionHandler == null) { throw new IllegalStateException("CompletionHandler argument cannot be null."); @@ -133,13 +133,10 @@ public boolean release(Connection connection) { // ---------------------------------------------------------- Nested Classes - public static final class MaxCapacityException extends IOException { public MaxCapacityException() { super("Maximum pool capacity has been reached"); } - } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 334dcac2ab..2971f0a59c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -58,56 +58,39 @@ public final class EventHandler { - private static final Map HANDLER_MAP = - new HashMap(); + private static final Map HANDLER_MAP = new HashMap(); static { - HANDLER_MAP.put(HttpStatus.UNAUTHORIZED_401.getStatusCode(), - AuthorizationHandler.INSTANCE); - HANDLER_MAP.put(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407.getStatusCode(), - ProxyAuthorizationHandler.INSTANCE); - HANDLER_MAP.put(HttpStatus.MOVED_PERMANENTLY_301.getStatusCode(), - RedirectHandler.INSTANCE); - HANDLER_MAP.put(HttpStatus.FOUND_302.getStatusCode(), - RedirectHandler.INSTANCE); - HANDLER_MAP.put(HttpStatus.TEMPORARY_REDIRECT_307.getStatusCode(), - RedirectHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.UNAUTHORIZED_401.getStatusCode(), AuthorizationHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407.getStatusCode(), ProxyAuthorizationHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.MOVED_PERMANENTLY_301.getStatusCode(), RedirectHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.FOUND_302.getStatusCode(), RedirectHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.TEMPORARY_REDIRECT_307.getStatusCode(), RedirectHandler.INSTANCE); } - private final AsyncHttpClientConfig config; GrizzlyAsyncHttpProvider.Cleanup cleanup; - // -------------------------------------------------------- Constructors - EventHandler(final AsyncHttpClientConfig config) { this.config = config; } - // ----------------------------------------------------- Event Callbacks - public void exceptionOccurred(FilterChainContext ctx, Throwable error) { HttpTxContext.get(ctx).abort(error); - } + public void onHttpContentParsed(HttpContent content, FilterChainContext ctx) { - public void onHttpContentParsed(HttpContent content, - FilterChainContext ctx) { - - final HttpTxContext context = - HttpTxContext.get(ctx); + final HttpTxContext context = HttpTxContext.get(ctx); final AsyncHandler handler = context.getHandler(); if (handler != null && context.getCurrentState() != ABORT) { try { - context.setCurrentState(handler.onBodyPartReceived( - new GrizzlyResponseBodyPart(content, - ctx.getConnection()))); + context.setCurrentState(handler.onBodyPartReceived(new GrizzlyResponseBodyPart(content, ctx.getConnection()))); } catch (Exception e) { handler.onThrowable(e); } @@ -117,8 +100,7 @@ public void onHttpContentParsed(HttpContent content, @SuppressWarnings("UnusedParameters") public void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ctx) { - final HttpTxContext context = - HttpTxContext.get(ctx); + final HttpTxContext context = HttpTxContext.get(ctx); final AsyncHandler handler = context.getHandler(); if (handler instanceof TransferCompletionHandler) { ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); @@ -126,19 +108,16 @@ public void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ctx) } public void onHttpContentEncoded(HttpContent content, FilterChainContext ctx) { - final HttpTxContext context = - HttpTxContext.get(ctx); + final HttpTxContext context = HttpTxContext.get(ctx); final AsyncHandler handler = context.getHandler(); if (handler instanceof TransferCompletionHandler) { final int written = content.getContent().remaining(); final long total = context.getTotalBodyWritten().addAndGet(written); - ((TransferCompletionHandler) handler).onContentWriteProgress( - written, total, content.getHttpHeader().getContentLength()); + ((TransferCompletionHandler) handler).onContentWriteProgress(written, total, content.getHttpHeader().getContentLength()); } } - public void onInitialLineParsed(HttpHeader httpHeader, - FilterChainContext ctx) { + public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) { //super.onInitialLineParsed(httpHeader, ctx); if (httpHeader.isSkipRemainder()) { @@ -184,16 +163,14 @@ public void onInitialLineParsed(HttpHeader httpHeader, } } } - final GrizzlyResponseStatus responseStatus = - new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, - context.getRequest().getURI(), - config); + final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, context.getRequest() + .getURI(), config); context.setResponseStatus(responseStatus); if (context.getStatusHandler() != null) { return; } - if (context.getCurrentState() != ABORT) { + if (context.getCurrentState() != ABORT) { try { final AsyncHandler handler = context.getHandler(); if (handler != null) { @@ -216,10 +193,7 @@ public void onInitialLineParsed(HttpHeader httpHeader, } - - public void onHttpHeaderError(final HttpHeader httpHeader, - final FilterChainContext ctx, - final Throwable t) { + public void onHttpHeaderError(final HttpHeader httpHeader, final FilterChainContext ctx, final Throwable t) { t.printStackTrace(); httpHeader.setSkipRemainder(true); @@ -227,9 +201,8 @@ public void onHttpHeaderError(final HttpHeader httpHeader, context.abort(t); } - @SuppressWarnings({"unchecked"}) - public void onHttpHeadersParsed(HttpHeader httpHeader, - FilterChainContext ctx) { + @SuppressWarnings({ "unchecked" }) + public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { //super.onHttpHeadersParsed(httpHeader, ctx); GrizzlyAsyncHttpProvider.LOGGER.debug("RESPONSE: {}", httpHeader); @@ -241,15 +214,11 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, } final AsyncHandler handler = context.getHandler(); - final GrizzlyResponseHeaders responseHeaders = - new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader); + final GrizzlyResponseHeaders responseHeaders = new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader); if (context.getProvider().getClientConfig().hasResponseFilters()) { - final List filters = context.getProvider() - .getClientConfig().getResponseFilters(); - FilterContext fc = new FilterContext.FilterContextBuilder() - .asyncHandler(handler).request(context.getRequest()) - .responseHeaders(responseHeaders) - .responseStatus(context.getResponseStatus()).build(); + final List filters = context.getProvider().getClientConfig().getResponseFilters(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(context.getRequest()) + .responseHeaders(responseHeaders).responseStatus(context.getResponseStatus()).build(); try { for (int i = 0, len = filters.size(); i < len; i++) { final ResponseFilter f = filters.get(i); @@ -263,20 +232,12 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, final Request newRequest = fc.getRequest(); final AsyncHandler newHandler = fc.getAsyncHandler(); try { - final ConnectionManager m = - context.getProvider().getConnectionManager(); - final Connection c = - m.obtainConnection(newRequest, - context.getFuture()); - final HttpTxContext newContext = - context.copy(); + final ConnectionManager m = context.getProvider().getConnectionManager(); + final Connection c = m.obtainConnection(newRequest, context.getFuture()); + final HttpTxContext newContext = context.copy(); newContext.setRequest(newRequest); context.setFuture(null); - context.getProvider().execute(c, - newRequest, - newHandler, - context.getFuture(), - newContext); + context.getProvider().execute(c, newRequest, newHandler, context.getFuture(), newContext); } catch (Exception e) { context.abort(e); } @@ -284,11 +245,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, } } if (context.getStatusHandler() != null && context.getInvocationStatus() == CONTINUE) { - final boolean result = - context.getStatusHandler().handleStatus( - ((HttpResponsePacket) httpHeader), - context, - ctx); + final boolean result = context.getStatusHandler().handleStatus(((HttpResponsePacket) httpHeader), context, ctx); if (!result) { httpHeader.setSkipRemainder(true); return; @@ -297,15 +254,13 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, if (context.isWSRequest()) { try { //in case of DIGEST auth protocol handler is null and just returning here is working - if(context.getProtocolHandler() == null) - { + if (context.getProtocolHandler() == null) { return; //context.protocolHandler = Version.DRAFT17.createHandler(true); //context.currentState = AsyncHandler.STATE.UPGRADE; } - context.getProtocolHandler().setConnection( - ctx.getConnection()); + context.getProtocolHandler().setConnection(ctx.getConnection()); final GrizzlyWebSocketAdapter webSocketAdapter = createWebSocketAdapter(context); context.setWebSocket(webSocketAdapter); @@ -313,23 +268,16 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, if (context.getCurrentState() == UPGRADE) { httpHeader.setChunked(false); ws.onConnect(); - WebSocketHolder.set(ctx.getConnection(), - context.getProtocolHandler(), - ws); + WebSocketHolder.set(ctx.getConnection(), context.getProtocolHandler(), ws); ((WebSocketUpgradeHandler) context.getHandler()).onSuccess(context.getWebSocket()); final int wsTimeout = context.getProvider().getClientConfig().getWebSocketIdleTimeoutInMs(); - IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), - ((wsTimeout <= 0) - ? IdleTimeoutFilter.FOREVER - : wsTimeout), - TimeUnit.MILLISECONDS); + IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER : wsTimeout), + TimeUnit.MILLISECONDS); context.result(handler.onCompleted()); } else { httpHeader.setSkipRemainder(true); - ((WebSocketUpgradeHandler) context.getHandler()). - onClose(context.getWebSocket(), - 1002, - "WebSocket protocol error: unexpected HTTP response status during handshake."); + ((WebSocketUpgradeHandler) context.getHandler()).onClose(context.getWebSocket(), 1002, + "WebSocket protocol error: unexpected HTTP response status during handshake."); context.result(null); } } catch (Exception e) { @@ -339,8 +287,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, } else { if (context.getCurrentState() != ABORT) { try { - context.setCurrentState( - handler.onHeadersReceived(responseHeaders)); + context.setCurrentState(handler.onHeadersReceived(responseHeaders)); } catch (Exception e) { httpHeader.setSkipRemainder(true); context.abort(e); @@ -350,7 +297,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, } - @SuppressWarnings("unchecked") + @SuppressWarnings("rawtypes") public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { Utils.removeRequestInFlight(ctx.getConnection()); @@ -381,11 +328,10 @@ public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) return false; } - // ----------------------------------------------------- Private Methods - private static void processKeepAlive(final Connection c, - final HttpHeader header) { + @SuppressWarnings("rawtypes") + private static void processKeepAlive(final Connection c, final HttpHeader header) { final ProcessingState state = header.getProcessingState(); final String connectionHeader = header.getHeader(Header.Connection); if (connectionHeader == null) { @@ -400,14 +346,14 @@ private static void processKeepAlive(final Connection c, } } - + @SuppressWarnings("rawtypes") private static GrizzlyWebSocketAdapter createWebSocketAdapter(final HttpTxContext context) { SimpleWebSocket ws = new SimpleWebSocket(context.getProtocolHandler()); AsyncHttpProviderConfig config = context.getProvider().getClientConfig().getAsyncHttpProviderConfig(); boolean bufferFragments = true; if (config instanceof GrizzlyAsyncHttpProviderConfig) { - bufferFragments = (Boolean) ((GrizzlyAsyncHttpProviderConfig) config).getProperty( - GrizzlyAsyncHttpProviderConfig.Property.BUFFER_WEBSOCKET_FRAGMENTS); + bufferFragments = (Boolean) ((GrizzlyAsyncHttpProviderConfig) config) + .getProperty(GrizzlyAsyncHttpProviderConfig.Property.BUFFER_WEBSOCKET_FRAGMENTS); } return new GrizzlyWebSocketAdapter(ws, bufferFragments); @@ -424,22 +370,21 @@ private static boolean isRedirectAllowed(final HttpTxContext ctx) { return allowed; } + @SuppressWarnings("rawtypes") private static HttpTxContext cleanup(final FilterChainContext ctx) { final Connection c = ctx.getConnection(); - final HttpTxContext context = - HttpTxContext.get(ctx); + final HttpTxContext context = HttpTxContext.get(ctx); HttpTxContext.remove(ctx, context); if (!Utils.isSpdyConnection(c) && !Utils.isIgnored(c)) { - final ConnectionManager manager = - context.getProvider().getConnectionManager(); + final ConnectionManager manager = context.getProvider().getConnectionManager(); //if (!manager.canReturnConnection(c)) { // context.abort( // new IOException("Maximum pooled connections exceeded")); //} else { - if (!manager.returnConnection(c)) { - ctx.getConnection().close(); - } + if (!manager.returnConnection(c)) { + ctx.getConnection().close(); + } //} } @@ -447,31 +392,21 @@ private static HttpTxContext cleanup(final FilterChainContext ctx) { } - private static boolean redirectCountExceeded(final HttpTxContext context) { - return (context.getRedirectCount().get() > context.getMaxRedirectCount()); - } - public static boolean isRedirect(final int status) { - return HttpStatus.MOVED_PERMANENTLY_301.statusMatches(status) - || HttpStatus.FOUND_302.statusMatches(status) - || HttpStatus.SEE_OTHER_303.statusMatches(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); - } - // ----------------------------------------------------- Private Methods - - public static Request newRequest(final URI uri, - final HttpResponsePacket response, - final HttpTxContext ctx, - boolean asGet) { + public static Request newRequest(final URI uri, final HttpResponsePacket response, final HttpTxContext ctx, boolean asGet) { final RequestBuilder builder = new RequestBuilder(ctx.getRequest()); if (asGet) { @@ -491,8 +426,6 @@ public static Request newRequest(final URI uri, } } return builder.build(); - } - } // END AsyncHttpClientEventFilter diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java index fd5965e812..cd6e52bb23 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java @@ -69,10 +69,8 @@ public class FeedableBodyGenerator implements BodyGenerator { private int configuredMaxPendingBytes = DEFAULT; private boolean asyncTransferInitiated; - // ---------------------------------------------- Methods from BodyGenerator - /** * {@inheritDoc} */ @@ -81,10 +79,8 @@ public Body createBody() throws IOException { return EMPTY_BODY; } - // ---------------------------------------------------------- Public Methods - /** * Configured the maximum number of bytes that may be pending to be written * to the wire. If not explicitly configured, the connection's current @@ -103,17 +99,14 @@ public Body createBody() throws IOException { @SuppressWarnings("UnusedDeclaration") public synchronized void setMaxPendingBytes(final int maxPendingBytes) { if (maxPendingBytes < DEFAULT) { - throw new IllegalArgumentException( - "Invalid maxPendingBytes value: " + maxPendingBytes); + 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."); + 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 @@ -127,35 +120,28 @@ public synchronized void setMaxPendingBytes(final int maxPendingBytes) { @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."); + 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."); + throw new IllegalArgumentException("Feeder argument cannot be null."); } this.feeder = feeder; } - // ------------------------------------------------- Package Private Methods - /** * Even though this method is public, it's not intended to be called by * Developers directly. Please avoid doing so. */ - public synchronized void initializeAsynchronousTransfer(final FilterChainContext context, - final HttpRequestPacket requestPacket) - throws IOException { + public synchronized void initializeAsynchronousTransfer(final FilterChainContext context, final HttpRequestPacket requestPacket) + throws IOException { if (asyncTransferInitiated) { - throw new IllegalStateException( - "Async transfer has already been initiated."); + throw new IllegalStateException("Async transfer has already been initiated."); } if (feeder == null) { - throw new IllegalStateException( - "No feeder available to perform the transfer."); + throw new IllegalStateException("No feeder available to perform the transfer."); } assert (context != null); assert (requestPacket != null); @@ -191,18 +177,14 @@ public void run() { } } - // --------------------------------------------------------- Private Methods - private boolean isServiceThread() { return Threads.isService(); } - // ----------------------------------------------------------- Inner Classes - private final class EmptyBody implements Body { @Override @@ -225,10 +207,8 @@ public void close() throws IOException { } // END EmptyBody - // ---------------------------------------------------------- Nested Classes - /** * Specifies the functionality all Feeders must implement. Typically, * developers need not worry about implementing this interface directly. @@ -268,7 +248,6 @@ public interface Feeder { } // END Feeder - /** * Base class for {@link Feeder} implementations. This class provides * an implementation for the contract defined by the {@link #feed} method. @@ -277,40 +256,28 @@ public static abstract class BaseFeeder implements Feeder { protected final FeedableBodyGenerator feedableBodyGenerator; - // -------------------------------------------------------- Constructors - protected BaseFeeder(FeedableBodyGenerator feedableBodyGenerator) { this.feedableBodyGenerator = feedableBodyGenerator; } - // --------------------------------------------- Package Private Methods - /** * {@inheritDoc} */ @SuppressWarnings("UnusedDeclaration") - public final synchronized void feed(final Buffer buffer, final boolean last) - throws IOException { + public final synchronized void feed(final Buffer buffer, final boolean last) throws IOException { if (buffer == null) { - throw new IllegalArgumentException( - "Buffer argument cannot be null."); + throw new IllegalArgumentException("Buffer argument cannot be null."); } if (!feedableBodyGenerator.asyncTransferInitiated) { - throw new IllegalStateException( - "Asynchronous transfer has not been initiated."); + throw new IllegalStateException("Asynchronous transfer has not been initiated."); } blockUntilQueueFree(feedableBodyGenerator.context); - final HttpContent content = - feedableBodyGenerator.contentBuilder - .content(buffer) - .last(last) - .build(); - final CompletionHandler handler = - ((last) ? new LastPacketCompletionHandler() : null); + final HttpContent content = feedableBodyGenerator.contentBuilder.content(buffer).last(last).build(); + final CompletionHandler handler = ((last) ? new LastPacketCompletionHandler() : null); feedableBodyGenerator.context.write(content, handler); } @@ -324,8 +291,7 @@ private static void blockUntilQueueFree(final FilterChainContext ctx) { HttpContext httpContext = HttpContext.get(ctx); final OutputSink outputSink = httpContext.getOutputSink(); if (!outputSink.canWrite()) { - final FutureImpl future = - Futures.createSafeFuture(); + final FutureImpl future = Futures.createSafeFuture(); outputSink.notifyCanWrite(new WriteHandler() { @Override @@ -343,11 +309,9 @@ public void onError(Throwable t) { } } - private static void block(final FilterChainContext ctx, - final FutureImpl future) { + private static void block(final FilterChainContext ctx, final FutureImpl future) { try { - final long writeTimeout = - ctx.getConnection().getTransport().getWriteTimeout(MILLISECONDS); + final long writeTimeout = ctx.getConnection().getTransport().getWriteTimeout(MILLISECONDS); if (writeTimeout != -1) { future.get(writeTimeout, MILLISECONDS); } else { @@ -362,12 +326,9 @@ private static void block(final FilterChainContext ctx, } } - // ------------------------------------------------------- Inner Classes - - private final class LastPacketCompletionHandler - implements CompletionHandler { + private final class LastPacketCompletionHandler implements CompletionHandler { private final CompletionHandler delegate; private final Connection c; @@ -375,22 +336,16 @@ private final class LastPacketCompletionHandler // -------------------------------------------------------- Constructors - @SuppressWarnings("unchecked") private LastPacketCompletionHandler() { - delegate = ((!feedableBodyGenerator.requestPacket.isCommitted()) - ? feedableBodyGenerator.context - .getTransportContext() - .getCompletionHandler() - : null); + delegate = ((!feedableBodyGenerator.requestPacket.isCommitted()) ? feedableBodyGenerator.context.getTransportContext() + .getCompletionHandler() : null); c = feedableBodyGenerator.context.getConnection(); origMaxPendingBytes = feedableBodyGenerator.origMaxPendingBytes; } - // -------------------------------------- Methods from CompletionHandler - @Override public void cancelled() { c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); @@ -428,7 +383,6 @@ public void updated(WriteResult result) { } // END Feeder - /** * Implementations of this class provide the framework to read data from * some source and feed data to the {@link FeedableBodyGenerator} @@ -437,10 +391,8 @@ public void updated(WriteResult result) { @SuppressWarnings("UnusedDeclaration") public static abstract class NonBlockingFeeder extends BaseFeeder { - // -------------------------------------------------------- Constructors - /** * Constructs the NonBlockingFeeder with the associated * {@link FeedableBodyGenerator}. @@ -449,10 +401,8 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { super(feedableBodyGenerator); } - // ------------------------------------------------------ Public Methods - /** * Notification that it's possible to send another block of data via * {@link #feed(org.glassfish.grizzly.Buffer, boolean)}. @@ -485,17 +435,14 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { */ public abstract void notifyReadyToFeed(final ReadyToFeedListener listener); - // ------------------------------------------------- Methods from Feeder - /** * {@inheritDoc} */ @Override public synchronized void flush() { - final HttpContext httpContext = - HttpContext.get(feedableBodyGenerator.context); + final HttpContext httpContext = HttpContext.get(feedableBodyGenerator.context); final OutputSink outputSink = httpContext.getOutputSink(); if (isReady()) { writeUntilFullOrDone(outputSink); @@ -514,10 +461,8 @@ public synchronized void flush() { } } - // ----------------------------------------------------- Private Methods - private void writeUntilFullOrDone(final OutputSink outputSink) { while (outputSink.canWrite()) { if (isReady()) { @@ -529,10 +474,8 @@ private void writeUntilFullOrDone(final OutputSink outputSink) { } } - // ------------------------------------------------------- Inner Classes - /** * Listener to signal that data is available to be fed. */ @@ -546,23 +489,18 @@ public interface ReadyToFeedListener { } // END ReadyToFeedListener - private final class WriteHandlerImpl implements WriteHandler { - private final Connection c; private final FilterChainContext ctx; - // -------------------------------------------------------- Constructors - private WriteHandlerImpl() { this.c = feedableBodyGenerator.context.getConnection(); this.ctx = feedableBodyGenerator.context; } - // ------------------------------------------ Methods from WriteListener @Override @@ -583,8 +521,7 @@ public void onWritePossible() throws Exception { @Override public void onError(Throwable t) { if (!Utils.isSpdyConnection(c)) { - c.setMaxAsyncWriteQueueSize( - feedableBodyGenerator.origMaxPendingBytes); + c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); } HttpTxContext httpTxContext = HttpTxContext.get(ctx); httpTxContext.abort(t); @@ -592,14 +529,10 @@ public void onError(Throwable t) { } // END WriteHandlerImpl - - private final class ReadyToFeedListenerImpl - implements NonBlockingFeeder.ReadyToFeedListener { - + private final class ReadyToFeedListenerImpl implements NonBlockingFeeder.ReadyToFeedListener { // ------------------------------------ Methods from ReadyToFeedListener - @Override public void ready() { flush(); @@ -609,7 +542,6 @@ public void ready() { } // END NonBlockingFeeder - /** * This simple {@link Feeder} implementation allows the implementation to * feed data in whatever fashion is deemed appropriate. @@ -617,10 +549,8 @@ public void ready() { @SuppressWarnings("UnusedDeclaration") public abstract static class SimpleFeeder extends BaseFeeder { - // -------------------------------------------------------- Constructors - /** * Constructs the SimpleFeeder with the associated * {@link FeedableBodyGenerator}. @@ -629,6 +559,5 @@ public SimpleFeeder(FeedableBodyGenerator feedableBodyGenerator) { super(feedableBodyGenerator); } - } // END SimpleFeeder } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 0225f79f50..a7d221093f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -94,10 +94,8 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { final TCPNIOTransport clientTransport; - // ------------------------------------------------------------ Constructors - public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { this.clientConfig = clientConfig; @@ -111,23 +109,20 @@ public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { } } - // ------------------------------------------ Methods from AsyncHttpProvider - /** * {@inheritDoc} */ - public ListenableFuture execute(final Request request, - final AsyncHandler handler) throws IOException { + 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()); - final CompletionHandler connectHandler = new CompletionHandler() { + future.setDelegate(SafeFutureImpl. create()); + final CompletionHandler connectHandler = new CompletionHandler() { @Override public void cancelled() { future.cancel(true); @@ -180,13 +175,13 @@ public void close() { threadPool.shutdownNow(); } } - } catch (IOException ignored) { } + } catch (IOException ignored) { + } } // ---------------------------------------------------------- Public Methods - public AsyncHttpClientConfig getClientConfig() { return clientConfig; } @@ -199,25 +194,18 @@ public DelayedExecutor.Resolver getResolver() { return resolver; } - // ------------------------------------------------------- Protected Methods - - @SuppressWarnings({"unchecked"}) - public ListenableFuture execute(final Connection c, - final Request request, - final AsyncHandler handler, - final GrizzlyResponseFuture future, - final HttpTxContext httpTxContext) { + @SuppressWarnings({ "unchecked" }) + public ListenableFuture execute(final Connection c, final Request request, final AsyncHandler handler, + final GrizzlyResponseFuture future, final HttpTxContext httpTxContext) { Utils.addRequestInFlight(c); - final RequestInfoHolder requestInfoHolder = - new RequestInfoHolder(this, request, handler, future, httpTxContext); + final RequestInfoHolder requestInfoHolder = new RequestInfoHolder(this, request, handler, future, httpTxContext); c.write(requestInfoHolder, createWriteCompletionHandler(future)); return future; } - void initializeTransport(final AsyncHttpClientConfig clientConfig) { final FilterChainBuilder secure = FilterChainBuilder.stateless(); @@ -235,25 +223,23 @@ void initializeTransport(final AsyncHttpClientConfig clientConfig) { } timeoutExecutor = IdleTimeoutFilter.createDefaultIdleDelayedExecutor(delay, TimeUnit.MILLISECONDS); timeoutExecutor.start(); - final IdleTimeoutFilter.TimeoutResolver timeoutResolver = - new IdleTimeoutFilter.TimeoutResolver() { - @Override - public long getTimeout(FilterChainContext ctx) { - final HttpTxContext context = HttpTxContext.get(ctx); - if (context != null) { - if (context.isWSRequest()) { - return clientConfig.getWebSocketIdleTimeoutInMs(); - } - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); - if (requestTimeout > 0) { - return requestTimeout; - } - } - return IdleTimeoutFilter.FOREVER; + final IdleTimeoutFilter.TimeoutResolver timeoutResolver = new IdleTimeoutFilter.TimeoutResolver() { + @Override + public long getTimeout(FilterChainContext ctx) { + final HttpTxContext context = HttpTxContext.get(ctx); + if (context != null) { + if (context.isWSRequest()) { + return clientConfig.getWebSocketIdleTimeoutInMs(); + } + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); + if (requestTimeout > 0) { + return requestTimeout; } - }; - final IdleTimeoutFilter timeoutFilter = new IdleTimeoutFilter(timeoutExecutor, - timeoutResolver, + } + return IdleTimeoutFilter.FOREVER; + } + }; + final IdleTimeoutFilter timeoutFilter = new IdleTimeoutFilter(timeoutExecutor, timeoutResolver, new IdleTimeoutFilter.TimeoutHandler() { public void onTimeout(Connection connection) { timeout(connection); @@ -271,15 +257,10 @@ public void onTimeout(Connection connection) { throw new IllegalStateException(e); } } - final SSLEngineConfigurator configurator = - new SSLEngineConfigurator(context, - true, - false, - false); + final SSLEngineConfigurator configurator = new SSLEngineConfigurator(context, true, false, false); final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator); secure.add(filter); - GrizzlyAsyncHttpProviderConfig providerConfig = - (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig(); + GrizzlyAsyncHttpProviderConfig providerConfig = (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig(); boolean npnEnabled = NextProtoNegSupport.isEnabled(); boolean spdyEnabled = clientConfig.isSpdyEnabled(); @@ -302,11 +283,7 @@ public void onTimeout(Connection connection) { final AsyncHttpClientEventFilter eventFilter; final EventHandler handler = new EventHandler(clientConfig); if (providerConfig != null) { - eventFilter = - new AsyncHttpClientEventFilter(handler, - (Integer) providerConfig - .getProperty( - MAX_HTTP_PACKET_HEADER_SIZE)); + eventFilter = new AsyncHttpClientEventFilter(handler, (Integer) providerConfig.getProperty(MAX_HTTP_PACKET_HEADER_SIZE)); } else { eventFilter = new AsyncHttpClientEventFilter(handler); } @@ -318,22 +295,16 @@ public void onTimeout(Connection connection) { } } if (clientConfig.isCompressionEnabled()) { - eventFilter.addContentEncoding( - new GZipContentEncoding(512, - 512, - new ClientEncodingFilter())); + eventFilter.addContentEncoding(new GZipContentEncoding(512, 512, new ClientEncodingFilter())); } secure.add(eventFilter); - final AsyncHttpClientFilter clientFilter = - new AsyncHttpClientFilter(this, clientConfig); + final AsyncHttpClientFilter clientFilter = new AsyncHttpClientFilter(this, clientConfig); secure.add(clientFilter); secure.add(new WebSocketClientFilter()); - clientTransport.getAsyncQueueIO().getWriter() - .setMaxPendingBytesPerConnection(AUTO_SIZE); + clientTransport.getAsyncQueueIO().getWriter().setMaxPendingBytesPerConnection(AUTO_SIZE); if (providerConfig != null) { - final TransportCustomizer customizer = (TransportCustomizer) - providerConfig.getProperty(Property.TRANSPORT_CUSTOMIZER); + final TransportCustomizer customizer = (TransportCustomizer) providerConfig.getProperty(Property.TRANSPORT_CUSTOMIZER); if (customizer != null) { customizer.customize(clientTransport, secure); } else { @@ -346,12 +317,9 @@ public void onTimeout(Connection connection) { // FilterChain for the standard HTTP case has been configured, we now // copy it and modify for SPDY purposes. if (spdyEnabled) { - FilterChainBuilder spdyFilterChain = - createSpdyFilterChain(secure, npnEnabled); - ProtocolNegotiator pn = - new ProtocolNegotiator(spdyFilterChain.build()); - NextProtoNegSupport.getInstance() - .setClientSideNegotiator(clientTransport, pn); + FilterChainBuilder spdyFilterChain = createSpdyFilterChain(secure, npnEnabled); + ProtocolNegotiator pn = new ProtocolNegotiator(spdyFilterChain.build()); + NextProtoNegSupport.getInstance().setClientSideNegotiator(clientTransport, pn); } // Install the HTTP filter chain. @@ -366,17 +334,12 @@ public void onTimeout(Connection connection) { } else { pool = null; } - connectionManager = new ConnectionManager(this, - pool, - secure, - nonSecure); + connectionManager = new ConnectionManager(this, pool, secure, nonSecure); } - // ------------------------------------------------- Package Private Methods - void touchConnection(final Connection c, final Request request) { int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, request); @@ -388,19 +351,15 @@ void touchConnection(final Connection c, final Request request) { } - // --------------------------------------------------------- Private Methods - - private FilterChainBuilder createSpdyFilterChain(final FilterChainBuilder fcb, - final boolean npnEnabled) { + private FilterChainBuilder createSpdyFilterChain(final FilterChainBuilder fcb, final boolean npnEnabled) { FilterChainBuilder spdyFcb = FilterChainBuilder.stateless(); spdyFcb.addAll(fcb); int idx = spdyFcb.indexOfType(SSLFilter.class); Filter f = spdyFcb.get(idx); - // Adjust the SSLFilter to support NPN if (npnEnabled) { SSLBaseFilter sslBaseFilter = (SSLBaseFilter) f; @@ -412,10 +371,8 @@ private FilterChainBuilder createSpdyFilterChain(final FilterChainBuilder fcb, idx = spdyFcb.indexOfType(HttpClientFilter.class); spdyFcb.set(idx, new SpdyFramingFilter()); final SpdyMode spdyMode = ((npnEnabled) ? SpdyMode.NPN : SpdyMode.PLAIN); - AsyncSpdyClientEventFilter spdyFilter = - new AsyncSpdyClientEventFilter(new EventHandler(clientConfig), - spdyMode, - clientConfig.executorService()); + AsyncSpdyClientEventFilter spdyFilter = new AsyncSpdyClientEventFilter(new EventHandler(clientConfig), spdyMode, + clientConfig.executorService()); spdyFilter.setInitialWindowSize(clientConfig.getSpdyInitialWindowSize()); spdyFilter.setMaxConcurrentStreams(clientConfig.getSpdyMaxConcurrentStreams()); spdyFcb.add(idx + 1, spdyFilter); @@ -427,9 +384,6 @@ private FilterChainBuilder createSpdyFilterChain(final FilterChainBuilder fcb, return spdyFcb; } - - - private void doDefaultTransportConfig() { final ExecutorService service = clientConfig.executorService(); clientTransport.setIOStrategy(WorkerThreadIOStrategy.getInstance()); @@ -438,9 +392,7 @@ private void doDefaultTransportConfig() { } else { final int multiplier = clientConfig.getIoThreadMultiplier(); final int threadCount = multiplier * Runtime.getRuntime().availableProcessors(); - clientTransport.getWorkerThreadPoolConfig() - .setCorePoolSize(threadCount) - .setMaxPoolSize(threadCount); + clientTransport.getWorkerThreadPoolConfig().setCorePoolSize(threadCount).setMaxPoolSize(threadCount); } } @@ -465,7 +417,6 @@ public void updated(WriteResult result) { }; } - void timeout(final Connection c) { final String key = HttpTxContext.class.getName(); @@ -480,27 +431,23 @@ void timeout(final Connection c) { throw new IllegalStateException(); } -// if (context != null) { -// HttpTxContext.set(c, null); -// context.abort(new TimeoutException("Timeout exceeded")); -// } + // if (context != null) { + // HttpTxContext.set(c, null); + // context.abort(new TimeoutException("Timeout exceeded")); + // } } - // ---------------------------------------------------------- Nested Classes - private static final class ProtocolNegotiator implements ClientSideNegotiator { - private static final String SPDY = "spdy/3"; private static final String HTTP = "HTTP/1.1"; private final FilterChain spdyFilterChain; private final SpdyHandlerFilter spdyHandlerFilter; - // -------------------------------------------------------- Constructors private ProtocolNegotiator(final FilterChain spdyFilterChain) { @@ -509,10 +456,8 @@ private ProtocolNegotiator(final FilterChain spdyFilterChain) { spdyHandlerFilter = (SpdyHandlerFilter) spdyFilterChain.get(idx); } - // ----------------------------------- Methods from ClientSideNegotiator - @Override public boolean wantNegotiate(SSLEngine engine) { GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::wantNegotiate"); @@ -528,11 +473,9 @@ public String selectProtocol(SSLEngine engine, LinkedHashSet strings) { // fallback if (strings.contains(SPDY)) { GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selecting: " + SPDY); - SSLConnectionContext sslCtx = - SSLUtils.getSslConnectionContext(connection); - sslCtx.setNewConnectionFilterChain(spdyFilterChain); - final SpdySession spdySession = - new SpdySession(connection, false, spdyHandlerFilter); + SSLConnectionContext sslCtx = SSLUtils.getSslConnectionContext(connection); + sslCtx.setNewConnectionFilterChain(spdyFilterChain); + final SpdySession spdySession = new SpdySession(connection, false, spdyHandlerFilter); spdySession.setLocalInitialWindowSize(spdyHandlerFilter.getInitialWindowSize()); spdySession.setLocalMaxConcurrentStreams(spdyHandlerFilter.getMaxConcurrentStreams()); Utils.setSpdyConnection(connection); @@ -558,14 +501,9 @@ public void onNoDeal(SSLEngine engine) { } } - public static interface Cleanup { void cleanup(final FilterChainContext ctx); } - } - - - diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java index 67d1362125..662eb6a5dd 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java @@ -31,7 +31,7 @@ * @author The Grizzly Team * @since 1.7.0 */ -public class GrizzlyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { +public class GrizzlyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { /** * Grizzly-specific customization properties. Each property describes @@ -74,34 +74,31 @@ public static enum Property { */ NPN_ENABLED(Boolean.class, true), - /** * Grizzly specific connection pool. */ CONNECTION_POOL(ConnectionPool.class, null); - - + final Object defaultValue; final Class type; - + private Property(final Class type, final Object defaultValue) { this.type = type; this.defaultValue = defaultValue; } - + private Property(final Class type) { this(type, null); } - + boolean hasDefaultValue() { return (defaultValue != null); } - - + } // END PROPERTY - - private final Map attributes = new HashMap(); - + + private final Map attributes = new HashMap(); + /** * @return true if the underlying provider should make new connections asynchronously or not. By default * new connections are made synchronously. @@ -140,12 +137,9 @@ public AsyncHttpProviderConfig addProperty(Property name, Object value) { } } else { if (!name.type.isAssignableFrom(value.getClass())) { - throw new IllegalArgumentException( - String.format( - "The value of property [%s] must be of type [%s]. Type of value provided: [%s].", - name.name(), - name.type.getName(), - value.getClass().getName())); + throw new IllegalArgumentException(String.format( + "The value of property [%s] must be of type [%s]. Type of value provided: [%s].", name.name(), + name.type.getName(), value.getClass().getName())); } } attributes.put(name, value); @@ -181,8 +175,7 @@ public Object removeProperty(Property name) { * {@inheritDoc} */ @Override - public Set> propertiesSet() { + public Set> propertiesSet() { return attributes.entrySet(); } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java index 058ae4ed4f..e6664c7d7c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java @@ -50,54 +50,39 @@ public class GrizzlyResponse extends ResponseBase { private Buffer responseBody; private boolean initialized; - // ------------------------------------------------------------ Constructors - - public GrizzlyResponse(final HttpResponseStatus status, - final HttpResponseHeaders headers, - final List bodyParts) { + public GrizzlyResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, final List bodyParts) { super(status, headers, bodyParts); } - - - // --------------------------------------------------- Methods from Response /** * {@inheritDoc} */ public InputStream getResponseBodyAsStream() throws IOException { - return new BufferInputStream(getResponseBody0()); - } - /** * {@inheritDoc} */ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - charset = calculateCharset(charset); + charset = calculateCharset(charset); final Buffer responseBody = getResponseBody0(); final int len = Math.min(responseBody.remaining(), maxLength); final int pos = responseBody.position(); return responseBody.toStringContent(getCharset(charset), pos, len + pos); - } - /** * {@inheritDoc} */ public String getResponseBody(String charset) throws IOException { - return getResponseBody0().toStringContent(getCharset(charset)); - } - /** * {@inheritDoc} */ @@ -120,19 +105,14 @@ public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { * {@inheritDoc} */ public String getResponseBodyExcerpt(int maxLength) throws IOException { - return getResponseBodyExcerpt(maxLength, null); - } - /** * {@inheritDoc} */ public String getResponseBody() throws IOException { - return getResponseBody(null); - } /** @@ -157,34 +137,24 @@ public List buildCookies() { return convertCookies(builder.build()); } else { - return Collections.unmodifiableList(Collections.emptyList()); + return Collections.unmodifiableList(Collections. emptyList()); } } // --------------------------------------------------------- Private Methods - private List convertCookies(Cookies cookies) { final org.glassfish.grizzly.http.Cookie[] grizzlyCookies = cookies.get(); List convertedCookies = new ArrayList(grizzlyCookies.length); for (int i = 0, len = grizzlyCookies.length; i < len; i++) { org.glassfish.grizzly.http.Cookie gCookie = grizzlyCookies[i]; - convertedCookies.add(new Cookie(gCookie.getName(), - gCookie.getValue(), - gCookie.getValue(), - gCookie.getDomain(), - gCookie.getPath(), - -1L, - gCookie.getMaxAge(), - gCookie.isSecure(), - gCookie.isHttpOnly())); + convertedCookies.add(new Cookie(gCookie.getName(), gCookie.getValue(), gCookie.getValue(), gCookie.getDomain(), gCookie + .getPath(), -1L, gCookie.getMaxAge(), gCookie.isSecure(), gCookie.isHttpOnly())); } return Collections.unmodifiableList(convertedCookies); - } - private Charset getCharset(final String charset) { String charsetLocal = charset; @@ -201,28 +171,20 @@ private Charset getCharset(final String charset) { } return Charsets.lookupCharset(charsetLocal); - } private synchronized Buffer getResponseBody0() { if (!initialized) { if (isNonEmpty(bodyParts)) { if (bodyParts.size() == 1) { - responseBody = ((GrizzlyResponseBodyPart) bodyParts.get( - 0)).getBodyBuffer(); + responseBody = ((GrizzlyResponseBodyPart) bodyParts.get(0)).getBodyBuffer(); } else { - final Buffer firstBuffer = - ((GrizzlyResponseBodyPart) bodyParts.get( - 0)).getBodyBuffer(); - final MemoryManager mm = - MemoryManager.DEFAULT_MEMORY_MANAGER; + final Buffer firstBuffer = ((GrizzlyResponseBodyPart) bodyParts.get(0)).getBodyBuffer(); + final MemoryManager mm = MemoryManager.DEFAULT_MEMORY_MANAGER; Buffer constructedBodyBuffer = firstBuffer; for (int i = 1, len = bodyParts.size(); i < len; i++) { - constructedBodyBuffer = - Buffers.appendBuffers(mm, - constructedBodyBuffer, - ((GrizzlyResponseBodyPart) bodyParts - .get(i)).getBodyBuffer()); + constructedBodyBuffer = Buffers.appendBuffers(mm, constructedBodyBuffer, + ((GrizzlyResponseBodyPart) bodyParts.get(i)).getBodyBuffer()); } responseBody = constructedBodyBuffer; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java index 82469fa80c..451ddae21e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseBodyPart.java @@ -36,24 +36,17 @@ class GrizzlyResponseBodyPart extends HttpResponseBodyPart { private final HttpContent content; private final Connection connection; - private final AtomicReference contentBytes = - new AtomicReference(); - + private final AtomicReference contentBytes = new AtomicReference(); // ------------------------------------------------------------ Constructors - - public GrizzlyResponseBodyPart(final HttpContent content, - final Connection connection) { + public GrizzlyResponseBodyPart(final HttpContent content, final Connection connection) { this.content = content; this.connection = connection; - } - // --------------------------------------- Methods from HttpResponseBodyPart - /** * {@inheritDoc} */ @@ -70,7 +63,6 @@ public byte[] getBodyPartBytes() { b.position(origPos); contentBytes.compareAndSet(null, bytes); return bytes; - } @Override @@ -82,7 +74,7 @@ public InputStream readBodyPartBytes() { public int length() { return content.getContent().remaining(); } - + /** * {@inheritDoc} */ @@ -92,18 +84,14 @@ public int writeTo(OutputStream outputStream) throws IOException { final byte[] bytes = getBodyPartBytes(); outputStream.write(bytes); return bytes.length; - } - /** * {@inheritDoc} */ @Override public ByteBuffer getBodyByteBuffer() { - return content.getContent().toByteBuffer(); - } /** @@ -130,14 +118,9 @@ public boolean isUnderlyingConnectionToBeClosed() { return !ConnectionManager.isConnectionCacheable(connection); } - // ----------------------------------------------- Package Protected Methods - Buffer getBodyBuffer() { - return content.getContent(); - } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java index d834ab6653..3a13110f78 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseFuture.java @@ -45,14 +45,10 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { FutureImpl delegate; - // ------------------------------------------------------------ Constructors - - public GrizzlyResponseFuture(final GrizzlyAsyncHttpProvider provider, - final Request request, - final AsyncHandler handler, - final ProxyServer proxyServer) { + public GrizzlyResponseFuture(final GrizzlyAsyncHttpProvider provider, final Request request, final AsyncHandler handler, + final ProxyServer proxyServer) { this.provider = provider; this.request = request; @@ -60,20 +56,16 @@ public GrizzlyResponseFuture(final GrizzlyAsyncHttpProvider provider, this.proxyServer = proxyServer; } - // ----------------------------------- Methods from AbstractListenableFuture - public void done() { if (!done.compareAndSet(false, true) || cancelled.get()) { return; } runListeners(); - } - public void abort(Throwable t) { if (done.get() || !cancelled.compareAndSet(false, true)) { @@ -88,37 +80,28 @@ public void abort(Throwable t) { } closeConnection(); runListeners(); - } public void touch() { - provider.touchConnection(connection, request); - } - public boolean getAndSetWriteHeaders(boolean writeHeaders) { // TODO This doesn't currently do anything - and may not make sense // with our implementation. Needs further analysis. return writeHeaders; - } - public boolean getAndSetWriteBody(boolean writeBody) { // TODO This doesn't currently do anything - and may not make sense // with our implementation. Needs further analysis. return writeBody; - } - // ----------------------------------------------------- Methods from Future - public boolean cancel(boolean mayInterruptIfRunning) { if (done.get() || !cancelled.compareAndSet(false, true)) { @@ -132,31 +115,20 @@ public boolean cancel(boolean mayInterruptIfRunning) { } runListeners(); return delegate.cancel(mayInterruptIfRunning); - } - public boolean isCancelled() { - return delegate.isCancelled(); - } - public boolean isDone() { - return delegate.isDone(); - } - public V get() throws InterruptedException, ExecutionException { - return delegate.get(); - } - public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (!delegate.isCancelled() || !delegate.isDone()) { @@ -164,36 +136,25 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution } else { return null; } - } - // ------------------------------------------------- Package Private Methods - void setConnection(final Connection connection) { - this.connection = connection; - } - public void setDelegate(final FutureImpl delegate) { - this.delegate = delegate; - } - // --------------------------------------------------------- Private Methods - private void closeConnection() { if (connection != null && connection.isOpen()) { connection.close().recycle(true); } - } public ProxyServer getProxyServer() { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java index b5aa6438b9..6e0893b16b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseHeaders.java @@ -18,7 +18,6 @@ import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.util.MimeHeaders; - /** * {@link HttpResponseHeaders} implementation using the Grizzly 2.0 HTTP client * codec. @@ -31,21 +30,16 @@ class GrizzlyResponseHeaders extends HttpResponseHeaders { private FluentCaseInsensitiveStringsMap headers; private MimeHeaders grizzlyHeaders; - // ------------------------------------------------------------ Constructors - public GrizzlyResponseHeaders(final HttpResponsePacket response) { grizzlyHeaders = new MimeHeaders(); grizzlyHeaders.copyFrom(response.getHeaders()); - } - // ---------------------------------------- Methods from HttpResponseHeaders - /** * {@inheritDoc} */ @@ -62,7 +56,6 @@ public synchronized FluentCaseInsensitiveStringsMap getHeaders() { return headers; } - @Override public String toString() { return getHeaders().toString(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java index f7d03dbf3b..65eb7dd1ad 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java @@ -39,14 +39,9 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { private final int minorVersion; private final String protocolText; - - // ------------------------------------------------------------ Constructors - - public GrizzlyResponseStatus(final HttpResponsePacket response, - final URI uri, - AsyncHttpClientConfig config) { + public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, AsyncHttpClientConfig config) { super(uri, config); statusCode = response.getStatus(); @@ -54,82 +49,60 @@ public GrizzlyResponseStatus(final HttpResponsePacket response, majorVersion = response.getProtocol().getMajorVersion(); minorVersion = response.getProtocol().getMinorVersion(); protocolText = response.getProtocolString(); - } - // ----------------------------------------- Methods from HttpResponseStatus @Override public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { - return new GrizzlyResponse(this, - headers, - bodyParts); + return new GrizzlyResponse(this, headers, bodyParts); } - + /** * {@inheritDoc} */ @Override public int getStatusCode() { - return statusCode; - } - /** * {@inheritDoc} */ @Override public String getStatusText() { - return statusText; - } - /** * {@inheritDoc} */ @Override public String getProtocolName() { - return PROTOCOL_NAME; - } - /** * {@inheritDoc} */ @Override public int getProtocolMajorVersion() { - return majorVersion; - } - /** * {@inheritDoc} */ @Override public int getProtocolMinorVersion() { - return minorVersion; - } - /** * {@inheritDoc} */ @Override public String getProtocolText() { - return protocolText; - } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index 766c233c6e..8ca71b1ce3 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java @@ -36,8 +36,8 @@ public final class HttpTxContext { - private static final Attribute REQUEST_STATE_ATTR = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTxContext.class.getName()); + private static final Attribute REQUEST_STATE_ATTR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER + .createAttribute(HttpTxContext.class.getName()); private final AtomicInteger redirectCount = new AtomicInteger(0); @@ -62,24 +62,19 @@ public final class HttpTxContext { private HandShake handshake; private ProtocolHandler protocolHandler; private WebSocket webSocket; - private CloseListener listener = new CloseListener< Closeable,CloseType>() { + private CloseListener listener = new CloseListener() { @Override - public void onClosed(Closeable closeable, CloseType type) - throws IOException { + public void onClosed(Closeable closeable, CloseType type) throws IOException { if (CloseType.REMOTELY.equals(type)) { abort(AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); } } }; - // -------------------------------------------------------- Constructors - - private HttpTxContext(final GrizzlyAsyncHttpProvider provider, - final GrizzlyResponseFuture future, - final Request request, - final AsyncHandler handler) { + private HttpTxContext(final GrizzlyAsyncHttpProvider provider, final GrizzlyResponseFuture future, final Request request, + final AsyncHandler handler) { this.provider = provider; this.future = future; this.request = request; @@ -87,22 +82,17 @@ private HttpTxContext(final GrizzlyAsyncHttpProvider provider, redirectsAllowed = this.provider.getClientConfig().isRedirectEnabled(); maxRedirectCount = this.provider.getClientConfig().getMaxRedirects(); this.requestUrl = request.getUrl(); - } - // ---------------------------------------------------------- Public Methods - - public static void set(final FilterChainContext ctx, - final HttpTxContext httpTxContext) { + public static void set(final FilterChainContext ctx, final HttpTxContext httpTxContext) { HttpContext httpContext = HttpContext.get(ctx); httpContext.getCloseable().addCloseListener(httpTxContext.listener); REQUEST_STATE_ATTR.set(httpContext, httpTxContext); } - public static void remove(final FilterChainContext ctx, - final HttpTxContext httpTxContext) { + public static void remove(final FilterChainContext ctx, final HttpTxContext httpTxContext) { HttpContext httpContext = HttpContext.get(ctx); httpContext.getCloseable().removeCloseListener(httpTxContext.listener); REQUEST_STATE_ATTR.remove(ctx); @@ -110,16 +100,14 @@ public static void remove(final FilterChainContext ctx, public static HttpTxContext get(FilterChainContext ctx) { HttpContext httpContext = HttpContext.get(ctx); - return ((httpContext != null) - ? REQUEST_STATE_ATTR.get(httpContext) - : null); + return ((httpContext != null) ? REQUEST_STATE_ATTR.get(httpContext) : null); } public static HttpTxContext create(final RequestInfoHolder requestInfoHolder) { - return new HttpTxContext(requestInfoHolder.getProvider(), - requestInfoHolder.getFuture(), - requestInfoHolder.getRequest(), - requestInfoHolder.getHandler()); + return new HttpTxContext(requestInfoHolder.getProvider(),// + requestInfoHolder.getFuture(),// + requestInfoHolder.getRequest(),// + requestInfoHolder.getHandler()); } public void abort(final Throwable t) { @@ -266,13 +254,8 @@ public void setWebSocket(WebSocket webSocket) { // ------------------------------------------------- Package Private Methods - public HttpTxContext copy() { - final HttpTxContext newContext = - new HttpTxContext(provider, - future, - request, - handler); + final HttpTxContext newContext = new HttpTxContext(provider, future, request, handler); newContext.invocationStatus = invocationStatus; newContext.bodyHandler = bodyHandler; newContext.currentState = currentState; @@ -280,7 +263,6 @@ public HttpTxContext copy() { newContext.lastRedirectURI = lastRedirectURI; newContext.redirectCount.set(redirectCount.get()); return newContext; - } void done() { @@ -289,12 +271,11 @@ void done() { } } - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({ "unchecked" }) void result(Object result) { if (future != null) { future.delegate.result(result); future.done(); } } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java index f7accfa634..c0e1b1fc4c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java @@ -26,7 +26,6 @@ import java.net.URI; - final class ProxyAwareConnectorHandler extends TCPNIOConnectorHandler { private FilterChainBuilder nonSecureTemplate; @@ -37,38 +36,27 @@ final class ProxyAwareConnectorHandler extends TCPNIOConnectorHandler { // ------------------------------------------------------------ Constructors - private ProxyAwareConnectorHandler(final TCPNIOTransport transport) { super(transport); } - // ---------------------------------------------------------- Public Methods - public static Builder builder(final TCPNIOTransport transport) { return new ProxyAwareConnectorHandler.Builder(transport); } - // ------------------------------------------- Methods from ConnectorHandler - @Override public Processor getProcessor() { - return ((proxyServer != null) - ? createProxyFilterChain() - : createFilterChain()); + return ((proxyServer != null) ? createProxyFilterChain() : createFilterChain()); } - // --------------------------------------------------------- Private Methods - private FilterChain createFilterChain() { - return Utils.isSecure(uri) - ? secureTemplate.build() - : nonSecureTemplate.build(); + return Utils.isSecure(uri) ? secureTemplate.build() : nonSecureTemplate.build(); } private FilterChain createProxyFilterChain() { @@ -96,26 +84,20 @@ private void updateNonSecureFilterChain(final FilterChainBuilder builder) { builder.add(idx + 1, new ProxyFilter(proxyServer, clientConfig, false)); } - // ---------------------------------------------------------- Nested Classes - public static final class Builder extends TCPNIOConnectorHandler.Builder { final ProxyAwareConnectorHandler connectorHandler; - // -------------------------------------------------------- Constructors - private Builder(final TCPNIOTransport transport) { connectorHandler = new ProxyAwareConnectorHandler(transport); } - // ----------------------------------------------------- Builder Methods - public Builder secureFilterChainTemplate(final FilterChainBuilder secureTemplate) { connectorHandler.secureTemplate = secureTemplate; return this; @@ -143,12 +125,11 @@ public Builder proxyServer(final ProxyServer proxyServer) { @Override public ProxyAwareConnectorHandler build() { - assert(connectorHandler.secureTemplate != null); - assert(connectorHandler.nonSecureTemplate != null); - assert(connectorHandler.clientConfig != null); - assert(connectorHandler.uri != null); + assert (connectorHandler.secureTemplate != null); + assert (connectorHandler.nonSecureTemplate != null); + assert (connectorHandler.clientConfig != null); + assert (connectorHandler.uri != null); return connectorHandler; } - } // END Builder } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/RequestInfoHolder.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/RequestInfoHolder.java index 7cf16c8ecd..94dfbdbd48 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/RequestInfoHolder.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/RequestInfoHolder.java @@ -24,15 +24,10 @@ public class RequestInfoHolder { private final GrizzlyResponseFuture future; private final HttpTxContext httpTxContext; - // ------------------------------------------------------------ Constructors - - public RequestInfoHolder(final GrizzlyAsyncHttpProvider provider, - final Request request, - final AsyncHandler handler, - final GrizzlyResponseFuture future, - final HttpTxContext httpTxContext) { + public RequestInfoHolder(final GrizzlyAsyncHttpProvider provider, final Request request, final AsyncHandler handler, + final GrizzlyResponseFuture future, final HttpTxContext httpTxContext) { this.provider = provider; this.request = request; this.handler = handler; @@ -40,10 +35,8 @@ public RequestInfoHolder(final GrizzlyAsyncHttpProvider provider, this.httpTxContext = httpTxContext; } - // ---------------------------------------------------------- Public Methods - public GrizzlyAsyncHttpProvider getProvider() { return provider; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/TransportCustomizer.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/TransportCustomizer.java index 8d86c4b398..34d5fe43f2 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/TransportCustomizer.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/TransportCustomizer.java @@ -38,7 +38,5 @@ public interface TransportCustomizer { * These filters should generally be left alone. But this does allow * adding additional filters to the chain to add additional features. */ - void customize(final TCPNIOTransport transport, - final FilterChainBuilder filterChainBuilder); - + void customize(final TCPNIOTransport transport, final FilterChainBuilder filterChainBuilder); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java index f54f828e1b..069652ef29 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java @@ -25,23 +25,19 @@ public final class Utils { - private static final Attribute IGNORE = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class.getName() + "-IGNORE"); - private static final Attribute REQUEST_IN_FLIGHT = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class.getName() + "-IN-FLIGHT"); - private static final Attribute SPDY = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class.getName() + "-SPDY-CONNECTION"); - + private static final Attribute IGNORE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class.getName() + "-IGNORE"); + private static final Attribute REQUEST_IN_FLIGHT = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class + .getName() + "-IN-FLIGHT"); + private static final Attribute SPDY = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(Utils.class.getName() + + "-SPDY-CONNECTION"); // ------------------------------------------------------------ Constructors - - private Utils() {} - + private Utils() { + } // ---------------------------------------------------------- Public Methods - public static boolean isSecure(final URI uri) { final String scheme = uri.getScheme(); return ("https".equals(scheme) || "wss".equals(scheme)); @@ -79,7 +75,7 @@ public static void removeRequestInFlight(final AttributeStorage storage) { public static int getRequestInFlightCount(final AttributeStorage storage) { AtomicInteger counter = REQUEST_IN_FLIGHT.get(storage); - return ((counter != null) ? counter.get() : 0); + return counter != null ? counter.get() : 0; } public static void setSpdyConnection(final Connection c) { @@ -88,16 +84,15 @@ public static void setSpdyConnection(final Connection c) { public static boolean isSpdyConnection(final Connection c) { Boolean result = SPDY.get(c); - return (result != null ? result : false); + return result != null ? result : false; } public 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)); - + return Method.POST.matchesMethod(method)// + || Method.PUT.matchesMethod(method)// + || Method.PATCH.matchesMethod(method)// + || Method.DELETE.matchesMethod(method); } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java index 287f309da1..f4c018337c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java @@ -30,16 +30,12 @@ public final class BodyGeneratorBodyHandler implements BodyHandler { // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(final Request request) { return (request.getBodyGenerator() != null); } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { final BodyGenerator generator = request.getBodyGenerator(); final Body bodyLocal = generator.createBody(); @@ -79,9 +75,7 @@ public boolean doHandle(final FilterChainContext ctx, } } - final HttpContent content = - requestPacket.httpContentBuilder().content(buffer). - last(last).build(); + final HttpContent content = requestPacket.httpContentBuilder().content(buffer).last(last).build(); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java index e476fdd264..44c907b9ba 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java @@ -25,8 +25,5 @@ public interface BodyHandler { boolean handlesBodyType(final Request request); - boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) throws IOException; - + boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java index ef43fc445e..44c7677e40 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java @@ -21,14 +21,14 @@ public final class BodyHandlerFactory { private final BodyHandler[] handlers; public BodyHandlerFactory(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { - handlers = new BodyHandler[]{ - new StringBodyHandler(grizzlyAsyncHttpProvider), - new ByteArrayBodyHandler(grizzlyAsyncHttpProvider), - new ParamsBodyHandler(grizzlyAsyncHttpProvider), - new StreamDataBodyHandler(), - new PartsBodyHandler(), - new FileBodyHandler(), - new BodyGeneratorBodyHandler() + handlers = new BodyHandler[] {// + new StringBodyHandler(grizzlyAsyncHttpProvider),// + new ByteArrayBodyHandler(grizzlyAsyncHttpProvider),// + new ParamsBodyHandler(grizzlyAsyncHttpProvider),// + new StreamDataBodyHandler(),// + new PartsBodyHandler(),// + new FileBodyHandler(),// + new BodyGeneratorBodyHandler() // }; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java index 603587fbe0..7731b92f26 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java @@ -32,27 +32,23 @@ public ByteArrayBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { compressionEnabled = grizzlyAsyncHttpProvider.getClientConfig().isCompressionEnabled(); } - // -------------------------------------------- Methods from BodyHandler public boolean handlesBodyType(final Request request) { return (request.getByteData() != null); } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { final byte[] data = request.getByteData(); final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { - if (!compressionEnabled) { - requestPacket.setContentLengthLong(data.length); - } + if (!compressionEnabled) { + requestPacket.setContentLengthLong(data.length); } + } final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java index dff737580a..cdb1553a03 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java @@ -27,22 +27,17 @@ public final class ExpectHandler implements BodyHandler { // -------------------------------------------------------- Constructors - public ExpectHandler(final BodyHandler delegate) { - this.delegate = delegate; - } - // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(Request request) { return delegate.handlesBodyType(request); } - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({ "unchecked" }) public boolean doHandle(FilterChainContext ctx, Request request, HttpRequestPacket requestPacket) throws IOException { this.request = request; this.requestPacket = requestPacket; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java index be3248d776..d957bf0ce6 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java @@ -39,19 +39,14 @@ public final class FileBodyHandler implements BodyHandler { SEND_FILE_SUPPORT = configSendFileSupport(); } - // ------------------------------------------------ Methods from BodyHandler - public boolean handlesBodyType(final Request request) { - return (request.getFile() != null); + return request.getFile() != null; } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); @@ -62,7 +57,7 @@ public boolean doHandle(final FilterChainContext ctx, AtomicInteger written = new AtomicInteger(); boolean last = false; try { - for (byte[] buf = new byte[MAX_CHUNK_SIZE]; !last; ) { + for (byte[] buf = new byte[MAX_CHUNK_SIZE]; !last;) { Buffer b = null; int read; if ((read = fis.read(buf)) < 0) { @@ -74,9 +69,7 @@ public boolean doHandle(final FilterChainContext ctx, b = Buffers.wrap(mm, buf, 0, read); } - final HttpContent content = - requestPacket.httpContentBuilder().content(b). - last(last).build(); + final HttpContent content = requestPacket.httpContentBuilder().content(b).last(last).build(); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } } finally { @@ -105,38 +98,28 @@ public void completed(WriteResult result) { return true; } - // --------------------------------------------------------- Private Methods - - private static void notifyHandlerIfNeeded(final HttpTxContext context, - final HttpRequestPacket requestPacket, - final WriteResult writeResult) { + private static void notifyHandlerIfNeeded(final HttpTxContext context, final HttpRequestPacket requestPacket, + final WriteResult writeResult) { final AsyncHandler handler = context.getHandler(); if (handler != null) { if (handler instanceof TransferCompletionHandler) { // WriteResult keeps a track of the total amount written, // so we need to calculate the delta ourselves. final long resultTotal = writeResult.getWrittenSize(); - final long written = - (resultTotal - context.getTotalBodyWritten().get()); + final long written = (resultTotal - context.getTotalBodyWritten().get()); final long total = context.getTotalBodyWritten().addAndGet(written); - ((TransferCompletionHandler) handler).onContentWriteProgress( - written, - total, - requestPacket.getContentLength()); + ((TransferCompletionHandler) handler).onContentWriteProgress(written, total, requestPacket.getContentLength()); } } } - private static boolean configSendFileSupport() { - return !((System.getProperty("os.name").equalsIgnoreCase("linux") - && !linuxSendFileSupported()) - || System.getProperty("os.name").equalsIgnoreCase("HP-UX")); + return !((System.getProperty("os.name").equalsIgnoreCase("linux") && !linuxSendFileSupported()) || System.getProperty("os.name") + .equalsIgnoreCase("HP-UX")); } - private static boolean linuxSendFileSupported() { final String version = System.getProperty("java.version"); if (version.startsWith("1.6")) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java index 55eef5fb54..879e894ea1 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java @@ -23,22 +23,16 @@ public 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 { + @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(); + final HttpContent content = requestPacket.httpContentBuilder().content(Buffers.EMPTY_BUFFER).build(); content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java index 374454e9d4..8cf8992e5c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java @@ -39,20 +39,15 @@ public ParamsBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { compressionEnabled = grizzlyAsyncHttpProvider.getClientConfig().isCompressionEnabled(); } - // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(final Request request) { final FluentStringsMap params = request.getParams(); return isNonEmpty(params); } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { if (requestPacket.getContentType() == null) { requestPacket.setContentType("application/x-www-form-urlencoded"); @@ -76,8 +71,7 @@ public boolean doHandle(final FilterChainContext ctx, if (sb.length() > 0) { sb.append('&'); } - sb.append(URLEncoder.encode(name, charset)) - .append('=').append(URLEncoder.encode(value, charset)); + sb.append(URLEncoder.encode(name, charset)).append('=').append(URLEncoder.encode(value, charset)); } } } @@ -97,5 +91,4 @@ public boolean doHandle(final FilterChainContext ctx, } return true; } - } // END ParamsBodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java index 90cfb80849..d7ffcd1683 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java @@ -35,27 +35,19 @@ public final class PartsBodyHandler implements BodyHandler { // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(final Request request) { return isNonEmpty(request.getParts()); } - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { final List parts = request.getParts(); final MultipartBody multipartBody = MultipartUtils.newMultipartBody(parts, request.getHeaders()); requestPacket.setContentLengthLong(multipartBody.getContentLength()); requestPacket.setContentType(multipartBody.getContentType()); if (GrizzlyAsyncHttpProvider.LOGGER.isDebugEnabled()) { - GrizzlyAsyncHttpProvider.LOGGER.debug( - "REQUEST(modified): contentLength={}, contentType={}", - new Object[]{ - requestPacket.getContentLength(), - requestPacket.getContentType() - }); + GrizzlyAsyncHttpProvider.LOGGER.debug("REQUEST(modified): contentLength={}, contentType={}", + new Object[] { requestPacket.getContentLength(), requestPacket.getContentType() }); } final FeedableBodyGenerator generator = new FeedableBodyGenerator() { @@ -74,8 +66,7 @@ public void flush() throws IOException { while (!last) { Buffer buffer = mm.allocate(BodyHandler.MAX_CHUNK_SIZE); buffer.allowBufferDispose(true); - final long readBytes = - bodyLocal.read(buffer.toByteBuffer()); + final long readBytes = bodyLocal.read(buffer.toByteBuffer()); if (readBytes > 0) { buffer.position((int) readBytes); buffer.trim(); @@ -85,8 +76,7 @@ public void flush() throws IOException { last = true; buffer = Buffers.EMPTY_BUFFER; } else { - throw new IllegalStateException( - "MultipartBody unexpectedly returned 0 bytes available"); + throw new IllegalStateException("MultipartBody unexpectedly returned 0 bytes available"); } } feed(buffer, last); @@ -103,7 +93,5 @@ public void flush() throws IOException { }); generator.initializeAsynchronousTransfer(ctx, requestPacket); return false; - } - } // END PartsBodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java index 320d846b9a..2647bd7c2a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java @@ -27,19 +27,14 @@ public final class StreamDataBodyHandler implements BodyHandler { - // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(final Request request) { return (request.getStreamData() != null); } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { final MemoryManager mm = ctx.getMemoryManager(); Buffer buffer = mm.allocate(512); @@ -70,8 +65,6 @@ public boolean doHandle(final FilterChainContext ctx, content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } - return true; } - } // END StreamDataBodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java index ab7e422270..bf1e54855e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java @@ -32,19 +32,14 @@ public StringBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { this.grizzlyAsyncHttpProvider = grizzlyAsyncHttpProvider; } - // -------------------------------------------- Methods from BodyHandler - public boolean handlesBodyType(final Request request) { return (request.getStringData() != null); } - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { + @SuppressWarnings({ "unchecked" }) + public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { String charset = request.getBodyEncoding(); if (charset == null) { @@ -63,5 +58,4 @@ public boolean doHandle(final FilterChainContext ctx, ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; } - } // END StringBodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java index 312fd0e07a..4de61df7d7 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java @@ -29,22 +29,17 @@ * @since 2.0 * @author The Grizzly Team */ -public final class AsyncHttpClientEventFilter extends HttpClientFilter - implements GrizzlyAsyncHttpProvider.Cleanup { - +public final class AsyncHttpClientEventFilter extends HttpClientFilter implements GrizzlyAsyncHttpProvider.Cleanup { private final EventHandler eventHandler; // -------------------------------------------------------- Constructors - public AsyncHttpClientEventFilter(final EventHandler eventHandler) { this(eventHandler, DEFAULT_MAX_HTTP_PACKET_HEADER_SIZE); } - - public AsyncHttpClientEventFilter(final EventHandler eventHandler, - final int maxHeaderSize) { + public AsyncHttpClientEventFilter(final EventHandler eventHandler, final int maxHeaderSize) { super(maxHeaderSize); this.eventHandler = eventHandler; @@ -94,5 +89,4 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c public void cleanup(final FilterChainContext ctx) { clearResponse(ctx.getConnection()); } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 2925b96b07..47b6007e25 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -96,7 +96,8 @@ public final class AsyncHttpClientFilter extends BaseFilter { private final GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider; private final BodyHandlerFactory bodyHandlerFactory; - private static final Attribute PROXY_AUTH_FAILURE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(AsyncHttpClientFilter.class.getName() + "-PROXY-AUTH_FAILURE"); + private static final Attribute PROXY_AUTH_FAILURE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER + .createAttribute(AsyncHttpClientFilter.class.getName() + "-PROXY-AUTH_FAILURE"); // -------------------------------------------------------- Constructors @@ -179,7 +180,6 @@ public Object onCompleted(Response response) throws Exception { } return ctx.getStopAction(); - } // ----------------------------------------------------- Private Methods @@ -282,27 +282,28 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, final Lock lock = session.getNewClientStreamLock(); try { lock.lock(); - SpdyStream stream = session.openStream(requestPacketLocal, session.getNextLocalStreamId(), 0, 0, 0, false, !requestPacketLocal.isExpectContent()); + SpdyStream stream = session.openStream(requestPacketLocal, session.getNextLocalStreamId(), 0, 0, 0, false, + !requestPacketLocal.isExpectContent()); HttpContext.newInstance(ctx, stream, stream, stream); } finally { lock.unlock(); } - } HttpTxContext.set(ctx, httpTxContext); return sendRequest(sendingCtx, request, requestPacketLocal); - } @SuppressWarnings("unchecked") - public boolean sendRequest(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { + public boolean sendRequest(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) + throws IOException { boolean isWriteComplete = true; if (Utils.requestHasEntityBody(request)) { final HttpTxContext context = HttpTxContext.get(ctx); BodyHandler handler = bodyHandlerFactory.getBodyHandler(request); - if (requestPacket.getHeaders().contains(Header.Expect) && requestPacket.getHeaders().getValue(1).equalsIgnoreCase("100-Continue")) { + if (requestPacket.getHeaders().contains(Header.Expect) + && requestPacket.getHeaders().getValue(1).equalsIgnoreCase("100-Continue")) { // We have to set the content-length now as the headers will be flushed // before the FileBodyHandler is invoked. If we don't do it here, and // the user didn't explicitly set the length, then the transfer-encoding @@ -374,8 +375,8 @@ private static boolean checkProxyAuthFailure(final FilterChainContext ctx, final private static FilterChainContext obtainProtocolChainContext(final FilterChainContext ctx, final FilterChain completeProtocolFilterChain) { - final FilterChainContext newFilterChainContext = completeProtocolFilterChain.obtainFilterChainContext(ctx.getConnection(), ctx.getStartIdx() + 1, - completeProtocolFilterChain.size(), ctx.getFilterIdx() + 1); + final FilterChainContext newFilterChainContext = completeProtocolFilterChain.obtainFilterChainContext(ctx.getConnection(), + ctx.getStartIdx() + 1, completeProtocolFilterChain.size(), ctx.getFilterIdx() + 1); newFilterChainContext.setAddressHolder(ctx.getAddressHolder()); newFilterChainContext.setMessage(ctx.getMessage()); @@ -446,7 +447,6 @@ private void addGeneralHeaders(final Request request, final HttpRequestPacket re if (!headers.contains(Header.UserAgent)) { requestPacket.addHeader(Header.UserAgent, config.getUserAgent()); } - } private void addCookies(final Request request, final HttpRequestPacket requestPacket) { @@ -459,7 +459,6 @@ private void addCookies(final Request request, final HttpRequestPacket requestPa CookieSerializerUtils.serializeClientCookies(sb, false, true, gCookies); requestPacket.addHeader(Header.Cookie, sb.toString()); } - } private static void convertCookies(final Collection cookies, final org.glassfish.grizzly.http.Cookie[] gCookies) { @@ -475,7 +474,6 @@ private static void convertCookies(final Collection cookies, final org.g idx++; } } - } private static void addQueryString(final Request request, final HttpRequestPacket requestPacket) { @@ -506,7 +504,6 @@ private static void addQueryString(final Request request, final HttpRequestPacke requestPacket.setQueryString(queryString); } - } class HttpRequestPacketImpl extends HttpRequestPacket { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java index e4741c4bb3..98a5f823b3 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java @@ -31,18 +31,13 @@ * @since 2.0 * @author The Grizzly Team */ -public final class AsyncSpdyClientEventFilter extends SpdyHandlerFilter - implements GrizzlyAsyncHttpProvider.Cleanup { - +public final class AsyncSpdyClientEventFilter extends SpdyHandlerFilter implements GrizzlyAsyncHttpProvider.Cleanup { private final EventHandler eventHandler; // -------------------------------------------------------- Constructors - - public AsyncSpdyClientEventFilter(final EventHandler eventHandler, - SpdyMode mode, - ExecutorService threadPool) { + public AsyncSpdyClientEventFilter(final EventHandler eventHandler, SpdyMode mode, ExecutorService threadPool) { super(mode, threadPool); this.eventHandler = eventHandler; } @@ -91,5 +86,4 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c public void cleanup(FilterChainContext ctx) { } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ClientEncodingFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ClientEncodingFilter.java index 332c0fb8c9..b3d7fa6439 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ClientEncodingFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ClientEncodingFilter.java @@ -27,25 +27,17 @@ */ public final class ClientEncodingFilter implements EncodingFilter { - // --------------------------------------------- Methods from EncodingFilter - public boolean applyEncoding(HttpHeader httpPacket) { - - httpPacket.addHeader(Header.AcceptEncoding, "gzip"); - return false; - + httpPacket.addHeader(Header.AcceptEncoding, "gzip"); + return false; } - public boolean applyDecoding(HttpHeader httpPacket) { final HttpResponsePacket httpResponse = (HttpResponsePacket) httpPacket; final DataChunk bc = httpResponse.getHeaders().getValue(Header.ContentEncoding); return bc != null && bc.indexOf("gzip", 0) != -1; - } - - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index 899e3af10d..5178d7dd4c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -44,29 +44,22 @@ public final class ProxyFilter extends BaseFilter { private final AsyncHttpClientConfig config; private final Boolean secure; - // ------------------------------------------------------------ Constructors - - public ProxyFilter(final ProxyServer proxyServer, - final AsyncHttpClientConfig config, - boolean secure) { + public ProxyFilter(final ProxyServer proxyServer, final AsyncHttpClientConfig config, boolean secure) { this.proxyServer = proxyServer; this.config = config; this.secure = secure; } - // ----------------------------------------------------- Methods from Filter - @Override - public NextAction handleWrite(FilterChainContext ctx) - throws IOException { + public NextAction handleWrite(FilterChainContext ctx) throws IOException { org.glassfish.grizzly.http.HttpContent content = ctx.getMessage(); HttpRequestPacket request = (HttpRequestPacket) content.getHttpHeader(); HttpTxContext context = HttpTxContext.get(ctx); - assert(context != null); + assert (context != null); Request req = context.getRequest(); if (!secure) { request.setRequestURI(req.getURI().toString()); @@ -75,12 +68,9 @@ public NextAction handleWrite(FilterChainContext ctx) return ctx.getInvokeAction(); } - // --------------------------------------------------------- Private Methods - - private void addProxyHeaders(final Realm realm, - final HttpRequestPacket request) { + private void addProxyHeaders(final Realm realm, final HttpRequestPacket request) { if (realm != null && realm.getUsePreemptiveAuth()) { final String authHeaderValue = generateAuthHeader(realm); if (authHeaderValue != null) { @@ -100,18 +90,17 @@ private Realm getRealm(final Request request) { private String generateAuthHeader(final Realm realm) { try { switch (realm.getAuthScheme()) { - case BASIC: - return computeBasicAuthentication(realm); - case DIGEST: - return computeDigestAuthentication(proxyServer); - case NTLM: - return NTLM_ENGINE.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); - default: - return null; + case BASIC: + return computeBasicAuthentication(realm); + case DIGEST: + return computeDigestAuthentication(proxyServer); + case NTLM: + return NTLM_ENGINE.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); + default: + return null; } } catch (Exception e) { throw new RuntimeException(e); } } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index 4ec3f6a25b..3085c950e8 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java @@ -31,7 +31,6 @@ import java.io.IOException; - /** * SSL Filter that may be present within the FilterChain and may be * enabled/disabled by sending the appropriate {@link SSLSwitchingEvent}. @@ -41,25 +40,19 @@ */ public final class SwitchingSSLFilter extends SSLFilter { - private static final Attribute CONNECTION_IS_SECURE = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SwitchingSSLFilter.class.getName()); - private static final Attribute HANDSHAKE_ERROR = - Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SwitchingSSLFilter.class.getName() + "-HANDSHAKE-ERROR"); - + private static final Attribute CONNECTION_IS_SECURE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER + .createAttribute(SwitchingSSLFilter.class.getName()); + private static final Attribute HANDSHAKE_ERROR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SwitchingSSLFilter.class + .getName() + "-HANDSHAKE-ERROR"); // ------------------------------------------------------------ Constructors - public SwitchingSSLFilter(final SSLEngineConfigurator clientConfig) { - super(null, clientConfig); - } - // -------------------------------------------------- Methods from SSLFilter - @Override protected void notifyHandshakeFailed(Connection connection, Throwable t) { setError(connection, t); @@ -73,35 +66,33 @@ public NextAction handleConnect(final FilterChainContext ctx) throws IOException // to determine if a connection is SPDY or HTTP as early as possible. ctx.suspend(); final Connection c = ctx.getConnection(); - handshake(ctx.getConnection(), - new EmptyCompletionHandler() { - @Override - public void completed(SSLEngine result) { - // Handshake was successful. Resume the handleConnect - // processing. We pass in Invoke Action so the filter - // chain will call handleConnect on the next filter. - ctx.resume(ctx.getInvokeAction()); - } - - @Override - public void cancelled() { - // Handshake was cancelled. Stop the handleConnect - // processing. The exception will be checked and - // passed to the user later. - setError(c, new SSLHandshakeException( - "Handshake canceled.")); - ctx.resume(ctx.getStopAction()); - } - - @Override - public void failed(Throwable throwable) { - // Handshake failed. Stop the handleConnect - // processing. The exception will be checked and - // passed to the user later. - setError(c, throwable); - ctx.resume(ctx.getStopAction()); - } - }); + handshake(ctx.getConnection(), new EmptyCompletionHandler() { + @Override + public void completed(SSLEngine result) { + // Handshake was successful. Resume the handleConnect + // processing. We pass in Invoke Action so the filter + // chain will call handleConnect on the next filter. + ctx.resume(ctx.getInvokeAction()); + } + + @Override + public void cancelled() { + // Handshake was cancelled. Stop the handleConnect + // processing. The exception will be checked and + // passed to the user later. + setError(c, new SSLHandshakeException("Handshake canceled.")); + ctx.resume(ctx.getStopAction()); + } + + @Override + public void failed(Throwable throwable) { + // Handshake failed. Stop the handleConnect + // processing. The exception will be checked and + // passed to the user later. + setError(c, throwable); + ctx.resume(ctx.getStopAction()); + } + }); // This typically isn't advised, however, we need to be able to // read the response from the proxy and OP_READ isn't typically @@ -115,8 +106,7 @@ public void failed(Throwable throwable) { } @Override - public NextAction handleEvent(final FilterChainContext ctx, - final FilterChainEvent event) throws IOException { + public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEvent event) throws IOException { if (event.type() == SSLSwitchingEvent.class) { final SSLSwitchingEvent se = (SSLSwitchingEvent) event; @@ -124,7 +114,6 @@ public NextAction handleEvent(final FilterChainContext ctx, return ctx.getStopAction(); } return ctx.getInvokeAction(); - } @Override @@ -134,7 +123,6 @@ public NextAction handleRead(final FilterChainContext ctx) throws IOException { return super.handleRead(ctx); } return ctx.getInvokeAction(); - } @Override @@ -144,7 +132,6 @@ public NextAction handleWrite(final FilterChainContext ctx) throws IOException { return super.handleWrite(ctx); } return ctx.getInvokeAction(); - } @Override @@ -152,15 +139,12 @@ public void onFilterChainChanged(final FilterChain filterChain) { // no-op } - public static Throwable getHandshakeError(final Connection c) { return HANDSHAKE_ERROR.remove(c); } - // --------------------------------------------------------- Private Methods - private static boolean isSecure(final Connection c) { Boolean secStatus = CONNECTION_IS_SECURE.get(c); return (secStatus == null ? true : secStatus); @@ -177,5 +161,4 @@ private static void setError(final Connection c, Throwable t) { private static void enableRead(final Connection c) throws IOException { c.enableIOEvent(IOEvent.READ); } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java index 4e4bd57bbc..081fd60314 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java @@ -38,22 +38,17 @@ public final class TunnelFilter extends BaseFilter { private final ProxyServer proxyServer; private final URI uri; - // ------------------------------------------------------------ Constructors - public TunnelFilter(final ProxyServer proxyServer, final URI uri) { this.proxyServer = proxyServer; this.uri = uri; } - // ----------------------------------------------------- Methods from Filter - @Override - public NextAction handleConnect(FilterChainContext ctx) - throws IOException { + public NextAction handleConnect(FilterChainContext ctx) throws IOException { // We suspend the FilterChainContext here to prevent // notification of other filters of the connection event. // This allows us to control when the connection is returned @@ -69,8 +64,7 @@ public NextAction handleConnect(FilterChainContext ctx) // When tunnel is complete, the AsyncHttpClientFilter will // send this event back to this filter in order to notify // it that the request processing is complete. - final TunnelRequestEvent tunnelRequestEvent = - new TunnelRequestEvent(ctx, proxyServer, uri); + final TunnelRequestEvent tunnelRequestEvent = new TunnelRequestEvent(ctx, proxyServer, uri); ctx.notifyUpstream(tunnelRequestEvent); // This typically isn't advised, however, we need to be able to @@ -85,8 +79,7 @@ public NextAction handleConnect(FilterChainContext ctx) } @Override - public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) - throws IOException { + public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) throws IOException { if (event.type() == TunnelRequestEvent.class) { TunnelRequestEvent tunnelRequestEvent = (TunnelRequestEvent) event; @@ -97,8 +90,7 @@ public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) // Obtain the context that was previously suspended and resume. // We pass in Invoke Action so the filter chain will call // handleConnect on the next filter. - FilterChainContext suspendedContext = - tunnelRequestEvent.getSuspendedContext(); + FilterChainContext suspendedContext = tunnelRequestEvent.getSuspendedContext(); suspendedContext.resume(ctx.getInvokeAction()); // Stop further event processing. @@ -106,5 +98,4 @@ public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) } return ctx.getInvokeAction(); } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/ContinueEvent.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/ContinueEvent.java index a7a710369f..c514d6677d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/ContinueEvent.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/ContinueEvent.java @@ -26,31 +26,22 @@ public final class ContinueEvent implements FilterChainEvent { private final HttpTxContext context; - // -------------------------------------------------------- Constructors - public ContinueEvent(final HttpTxContext context) { - this.context = context; - } - // --------------------------------------- Methods from FilterChainEvent - @Override public Object type() { return ContinueEvent.class; } - // ---------------------------------------------------------- Public Methods - public HttpTxContext getContext() { return context; } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/SSLSwitchingEvent.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/SSLSwitchingEvent.java index 17612dc953..5fad70d100 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/SSLSwitchingEvent.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/SSLSwitchingEvent.java @@ -16,7 +16,6 @@ import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.filterchain.FilterChainEvent; - /** * {@link FilterChainEvent} to dynamically enable/disable the SSLFilter on * a per-connection basis. @@ -31,26 +30,20 @@ public final class SSLSwitchingEvent implements FilterChainEvent { // ------------------------------------------------------------ Constructors - public SSLSwitchingEvent(final boolean secure, final Connection c) { - this.secure = secure; connection = c; - } // ------------------------------------------- Methods from FilterChainEvent - @Override public Object type() { return SSLSwitchingEvent.class; } - // ---------------------------------------------------------- Public Methods - public boolean isSecure() { return secure; } @@ -58,5 +51,4 @@ public boolean isSecure() { public Connection getConnection() { return connection; } - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java index fc0285c962..41f49894c4 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java @@ -26,35 +26,27 @@ */ public final class TunnelRequestEvent implements FilterChainEvent { - private final FilterChainContext suspendedContext; private final ProxyServer proxyServer; private final URI uri; - // ------------------------------------------------------------ Constructors - public TunnelRequestEvent(final FilterChainContext suspendedContext, - final ProxyServer proxyServer, - final URI uri) { + public TunnelRequestEvent(final FilterChainContext suspendedContext, final ProxyServer proxyServer, final URI uri) { this.suspendedContext = suspendedContext; this.proxyServer = proxyServer; this.uri = uri; } - // ------------------------------------------- Methods from FilterChainEvent - @Override public Object type() { return TunnelRequestEvent.class; } - // ---------------------------------------------------------- Public Methods - public FilterChainContext getSuspendedContext() { return suspendedContext; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java index 5f99182e7f..8bebb92d5d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java @@ -31,20 +31,17 @@ public final class AuthorizationHandler implements StatusHandler { - public static final AuthorizationHandler INSTANCE = - new AuthorizationHandler(); + public static final AuthorizationHandler INSTANCE = new AuthorizationHandler(); // ---------------------------------------------- Methods from StatusHandler - public boolean handlesStatus(int statusCode) { return (HttpStatus.UNAUTHORIZED_401.statusMatches(statusCode)); } - @SuppressWarnings({"unchecked"}) - public boolean handleStatus(final HttpResponsePacket responsePacket, - final HttpTxContext httpTransactionContext, - final FilterChainContext ctx) { + @SuppressWarnings({ "unchecked" }) + public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpTxContext httpTransactionContext, + final FilterChainContext ctx) { final String auth = responsePacket.getHeader(Header.WWWAuthenticate); if (auth == null) { @@ -59,8 +56,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, httpTransactionContext.setInvocationStatus(STOP); if (httpTransactionContext.getHandler() != null) { try { - httpTransactionContext.getHandler().onStatusReceived( - httpTransactionContext.getResponseStatus()); + httpTransactionContext.getHandler().onStatusReceived(httpTransactionContext.getResponseStatus()); } catch (Exception e) { httpTransactionContext.abort(e); } @@ -71,24 +67,16 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, responsePacket.setSkipRemainder(true); // ignore the remainder of the response final Request req = httpTransactionContext.getRequest(); - realm = new Realm.RealmBuilder().clone(realm) - .setScheme(realm.getAuthScheme()) - .setUri(req.getURI().getPath()) - .setMethodName(req.getMethod()) - .setUsePreemptiveAuth(true) - .parseWWWAuthenticateHeader(auth) - .build(); + realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getURI().getPath()) + .setMethodName(req.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(auth).build(); String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH); if (lowerCaseAuth.startsWith("basic")) { req.getHeaders().remove(Header.Authorization.toString()); - req.getHeaders().add(Header.Authorization.toString(), - AuthenticatorUtils.computeBasicAuthentication( - realm)); + 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)); + req.getHeaders().add(Header.Authorization.toString(), AuthenticatorUtils.computeDigestAuthentication(realm)); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("Digest authentication not supported", e); } @@ -96,22 +84,14 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, throw new IllegalStateException("Unsupported authorization method: " + auth); } - try { - final Connection c = getConnectionForNextRequest(ctx, - req, - responsePacket, - httpTransactionContext); - final HttpTxContext newContext = - httpTransactionContext.copy(); + final Connection c = getConnectionForNextRequest(ctx, req, responsePacket, httpTransactionContext); + final HttpTxContext newContext = httpTransactionContext.copy(); httpTransactionContext.setFuture(null); HttpTxContext.set(ctx, newContext); newContext.setInvocationStatus(STOP); - httpTransactionContext.getProvider().execute(c, - req, - httpTransactionContext.getHandler(), - httpTransactionContext.getFuture(), - newContext); + httpTransactionContext.getProvider().execute(c, req, httpTransactionContext.getHandler(), httpTransactionContext.getFuture(), + newContext); return false; } catch (Exception e) { httpTransactionContext.abort(e); @@ -120,21 +100,16 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, return false; } - // --------------------------------------------------------- Private Methods - - private Connection getConnectionForNextRequest(final FilterChainContext ctx, - final Request request, - final HttpResponsePacket response, - final HttpTxContext httpCtx) - throws Exception { + private Connection getConnectionForNextRequest(final FilterChainContext ctx, final Request request, final HttpResponsePacket response, + final HttpTxContext httpCtx) throws Exception { /* if (response.getProcessingState().isKeepAlive()) { return ctx.getConnection(); } else { */ - final ConnectionManager m = httpCtx.getProvider().getConnectionManager(); - return m.obtainConnection(request, httpCtx.getFuture()); + final ConnectionManager m = httpCtx.getProvider().getConnectionManager(); + return m.obtainConnection(request, httpCtx.getFuture()); /* } */ } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java index 9dcd692a06..313770759d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java @@ -39,60 +39,41 @@ public final class ProxyAuthorizationHandler implements StatusHandler { - public static final ProxyAuthorizationHandler INSTANCE = - new ProxyAuthorizationHandler(); - + public static final ProxyAuthorizationHandler INSTANCE = new ProxyAuthorizationHandler(); // ---------------------------------------------- Methods from StatusHandler - public boolean handlesStatus(int statusCode) { - return (HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407 - .statusMatches(statusCode)); + return (HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407.statusMatches(statusCode)); } - public boolean handleStatus(final HttpResponsePacket responsePacket, - final HttpTxContext httpTransactionContext, - final FilterChainContext ctx) { + public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpTxContext httpTransactionContext, + final FilterChainContext ctx) { - final String proxyAuth = - responsePacket.getHeader(Header.ProxyAuthenticate); + final String proxyAuth = responsePacket.getHeader(Header.ProxyAuthenticate); if (proxyAuth == null) { - throw new IllegalStateException( - "407 response received, but no Proxy Authenticate header was present"); + throw new IllegalStateException("407 response received, but no Proxy Authenticate header was present"); } final Request req = httpTransactionContext.getRequest(); - ProxyServer proxyServer = httpTransactionContext.getProvider() - .getClientConfig() - .getProxyServerSelector() + ProxyServer proxyServer = httpTransactionContext.getProvider().getClientConfig().getProxyServerSelector() .select(req.getOriginalURI()); String principal = proxyServer.getPrincipal(); String password = proxyServer.getPassword(); - Realm realm = new Realm.RealmBuilder().setPrincipal(principal) - .setPassword(password) - .setUri("/") - .setMethodName(Method.CONNECT.getMethodString()) - .setUsePreemptiveAuth(true) - .parseProxyAuthenticateHeader(proxyAuth) - .build(); + Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri("/") + .setMethodName(Method.CONNECT.getMethodString()).setUsePreemptiveAuth(true).parseProxyAuthenticateHeader(proxyAuth).build(); String proxyAuthLowerCase = proxyAuth.toLowerCase(Locale.ENGLISH); if (proxyAuthLowerCase.startsWith("basic")) { req.getHeaders().remove(Header.ProxyAuthenticate.toString()); req.getHeaders().remove(Header.ProxyAuthorization.toString()); - req.getHeaders().add(Header.ProxyAuthorization.toString(), - AuthenticatorUtils.computeBasicAuthentication( - realm)); + req.getHeaders().add(Header.ProxyAuthorization.toString(), AuthenticatorUtils.computeBasicAuthentication(realm)); } else if (proxyAuthLowerCase.startsWith("digest")) { req.getHeaders().remove(Header.ProxyAuthenticate.toString()); req.getHeaders().remove(Header.ProxyAuthorization.toString()); try { - req.getHeaders().add(Header.ProxyAuthorization.toString(), - AuthenticatorUtils.computeDigestAuthentication( - realm)); + req.getHeaders().add(Header.ProxyAuthorization.toString(), AuthenticatorUtils.computeDigestAuthentication(realm)); } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException( - "Digest authentication not supported", e); + throw new IllegalStateException("Digest authentication not supported", e); } } else if (proxyAuthLowerCase.startsWith("ntlm")) { @@ -102,21 +83,14 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, String msg; try { if (isNTLMFirstHandShake(proxyAuth)) { - msg = GrizzlyAsyncHttpProvider.NTLM_ENGINE - .generateType1Msg(proxyServer.getNtlmDomain(), ""); + msg = GrizzlyAsyncHttpProvider.NTLM_ENGINE.generateType1Msg(proxyServer.getNtlmDomain(), ""); } else { - String serverChallenge = - proxyAuth.trim().substring("NTLM ".length()); - msg = GrizzlyAsyncHttpProvider.NTLM_ENGINE - .generateType3Msg(principal, password, - proxyServer.getNtlmDomain(), - proxyServer.getHost(), - serverChallenge); + String serverChallenge = proxyAuth.trim().substring("NTLM ".length()); + msg = GrizzlyAsyncHttpProvider.NTLM_ENGINE.generateType3Msg(principal, password, proxyServer.getNtlmDomain(), + proxyServer.getHost(), serverChallenge); } - req.getHeaders() - .add(Header.ProxyAuthorization.toString(), - "NTLM " + msg); + req.getHeaders().add(Header.ProxyAuthorization.toString(), "NTLM " + msg); } catch (Exception e1) { e1.printStackTrace(); } @@ -125,8 +99,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, req.getHeaders().remove(Header.ProxyAuthenticate.toString()); req.getHeaders().remove(Header.ProxyAuthorization.toString()); } else { - throw new IllegalStateException( - "Unsupported authorization method: " + proxyAuth); + throw new IllegalStateException("Unsupported authorization method: " + proxyAuth); } InvocationStatus tempInvocationStatus = InvocationStatus.STOP; @@ -136,12 +109,8 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, tempInvocationStatus = InvocationStatus.CONTINUE; } if (proxyAuth.toLowerCase().startsWith("negotiate")) { - final Connection c = getConnectionForNextRequest(ctx, - req, - responsePacket, - httpTransactionContext); - final HttpTxContext newContext = - httpTransactionContext.copy(); + final Connection c = getConnectionForNextRequest(ctx, req, responsePacket, httpTransactionContext); + final HttpTxContext newContext = httpTransactionContext.copy(); httpTransactionContext.setFuture(null); HttpTxContext.set(ctx, newContext); @@ -152,16 +121,12 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, challengeHeader = GSSSPNEGOWrapper.generateToken(server); - req.getHeaders() - .add(Header.ProxyAuthorization.toString(), - "Negotiate " + challengeHeader); - + req.getHeaders().add(Header.ProxyAuthorization.toString(), "Negotiate " + challengeHeader); return executeRequest(httpTransactionContext, req, c, newContext); } else if (isNTLMSecondHandShake(proxyAuth)) { final Connection c = ctx.getConnection(); - final HttpTxContext newContext = - httpTransactionContext.copy(); + final HttpTxContext newContext = httpTransactionContext.copy(); httpTransactionContext.setFuture(null); HttpTxContext.set(ctx, newContext); @@ -171,12 +136,8 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, return executeRequest(httpTransactionContext, req, c, newContext); } else { - final Connection c = getConnectionForNextRequest(ctx, - req, - responsePacket, - httpTransactionContext); - final HttpTxContext newContext = - httpTransactionContext.copy(); + final Connection c = getConnectionForNextRequest(ctx, req, responsePacket, httpTransactionContext); + final HttpTxContext newContext = httpTransactionContext.copy(); httpTransactionContext.setFuture(null); HttpTxContext.set(ctx, newContext); @@ -192,63 +153,48 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, return false; } - private boolean executeRequest( - final HttpTxContext httpTransactionContext, - final Request req, final Connection c, final HttpTxContext httpTxContext) { - httpTransactionContext.getProvider().execute(c, - req, - httpTransactionContext.getHandler(), - httpTransactionContext.getFuture(), - httpTxContext); - return false; + private boolean executeRequest(final HttpTxContext httpTransactionContext, final Request req, final Connection c, + final HttpTxContext httpTxContext) { + httpTransactionContext.getProvider().execute(c, req, httpTransactionContext.getHandler(), httpTransactionContext.getFuture(), + httpTxContext); + return false; } public static boolean isNTLMSecondHandShake(final String proxyAuth) { - return (proxyAuth != null && proxyAuth.toLowerCase(Locale.ENGLISH) - .startsWith("ntlm") && !proxyAuth.equalsIgnoreCase("ntlm")); + return (proxyAuth != null && proxyAuth.toLowerCase(Locale.ENGLISH).startsWith("ntlm") && !proxyAuth.equalsIgnoreCase("ntlm")); } private static boolean isNTLMFirstHandShake(final String proxy_auth) { return (proxy_auth.equalsIgnoreCase("ntlm")); } - private Connection getConnectionForNextRequest(final FilterChainContext ctx, - final Request request, - final HttpResponsePacket response, - final HttpTxContext httpCtx) - throws Exception { + private Connection getConnectionForNextRequest(final FilterChainContext ctx, final Request request, final HttpResponsePacket response, + final HttpTxContext httpCtx) throws Exception { /* if (response.getProcessingState().isKeepAlive()) { return ctx.getConnection(); } else { */ - final ConnectionManager m = httpCtx.getProvider().getConnectionManager(); - return m.obtainConnection(request, httpCtx.getFuture()); - /* } */ + final ConnectionManager m = httpCtx.getProvider().getConnectionManager(); + return m.obtainConnection(request, httpCtx.getFuture()); + /* } */ } - private static final class GSSSPNEGOWrapper { - private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger( - GSSSPNEGOWrapper.class); + private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(GSSSPNEGOWrapper.class); private static final String KERBEROS_OID = "1.2.840.113554.1.2.2"; static GSSManager getManager() { return GSSManager.getInstance(); } - static byte[] generateGSSToken( - final byte[] input, final Oid oid, final String authServer) - throws GSSException { + static byte[] generateGSSToken(final byte[] input, final Oid oid, final String authServer) throws GSSException { byte[] token = input; if (token == null) { token = new byte[0]; } GSSManager manager = getManager(); - GSSName serverName = manager.createName("HTTP@" + authServer, - GSSName.NT_HOSTBASED_SERVICE); - GSSContext gssContext = manager.createContext( - serverName.canonicalize(oid), oid, null, - GSSContext.DEFAULT_LIFETIME); + GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE); + GSSContext gssContext = manager.createContext(serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME); gssContext.requestMutualAuth(true); gssContext.requestCredDeleg(true); return gssContext.initSecContext(token, 0, token.length); @@ -259,8 +205,7 @@ public static String generateToken(String authServer) { Oid oid; try { oid = new Oid(KERBEROS_OID); - byte[] token = GSSSPNEGOWrapper.generateGSSToken(null, oid, - authServer); + byte[] token = GSSSPNEGOWrapper.generateGSSToken(null, oid, authServer); returnVal = Base64.encode(token); } catch (GSSException e) { LOGGER.warn(e.toString(), e); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java index 1d9f566363..c7bd5d514b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java @@ -31,18 +31,15 @@ public final class RedirectHandler implements StatusHandler { public static final RedirectHandler INSTANCE = new RedirectHandler(); - // ------------------------------------------ Methods from StatusHandler - public boolean handlesStatus(int statusCode) { return (EventHandler.isRedirect(statusCode)); } - @SuppressWarnings({"unchecked"}) - public boolean handleStatus(final HttpResponsePacket responsePacket, - final HttpTxContext httpTransactionContext, - final FilterChainContext ctx) { + @SuppressWarnings({ "unchecked" }) + public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpTxContext httpTransactionContext, + final FilterChainContext ctx) { final String redirectURL = responsePacket.getHeader(Header.Location); if (redirectURL == null) { @@ -53,48 +50,36 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, if (httpTransactionContext.getLastRedirectURI() == null) { orig = httpTransactionContext.getRequest().getURI(); } else { - orig = AsyncHttpProviderUtils.getRedirectUri( - httpTransactionContext.getRequest().getURI(), + orig = AsyncHttpProviderUtils.getRedirectUri(httpTransactionContext.getRequest().getURI(), httpTransactionContext.getLastRedirectURI()); } httpTransactionContext.setLastRedirectURI(redirectURL); Request requestToSend; URI uri = AsyncHttpProviderUtils.getRedirectUri(orig, redirectURL); if (!uri.toString().equalsIgnoreCase(orig.toString())) { - requestToSend = EventHandler - .newRequest(uri, - responsePacket, - httpTransactionContext, - sendAsGet( - responsePacket, - httpTransactionContext)); + requestToSend = EventHandler.newRequest(uri, responsePacket, httpTransactionContext, + sendAsGet(responsePacket, httpTransactionContext)); } else { httpTransactionContext.setStatusHandler(null); httpTransactionContext.setInvocationStatus(CONTINUE); - try { - httpTransactionContext.getHandler().onStatusReceived(httpTransactionContext.getResponseStatus()); - } catch (Exception e) { - httpTransactionContext.abort(e); - } + try { + httpTransactionContext.getHandler().onStatusReceived(httpTransactionContext.getResponseStatus()); + } catch (Exception e) { + httpTransactionContext.abort(e); + } return true; } final ConnectionManager m = httpTransactionContext.getProvider().getConnectionManager(); try { - final Connection c = m.obtainConnection(requestToSend, - httpTransactionContext.getFuture()); - final HttpTxContext newContext = - httpTransactionContext.copy(); + final Connection c = m.obtainConnection(requestToSend, httpTransactionContext.getFuture()); + final HttpTxContext newContext = httpTransactionContext.copy(); httpTransactionContext.setFuture(null); newContext.setInvocationStatus(CONTINUE); newContext.setRequest(requestToSend); newContext.setRequestUrl(requestToSend.getUrl()); HttpTxContext.set(ctx, newContext); - httpTransactionContext.getProvider().execute(c, - requestToSend, - newContext.getHandler(), - newContext.getFuture(), - newContext); + httpTransactionContext.getProvider().execute(c, requestToSend, newContext.getHandler(), newContext.getFuture(), newContext); return false; } catch (Exception e) { httpTransactionContext.abort(e); @@ -105,15 +90,11 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, } - // ------------------------------------------------- Private Methods - private boolean sendAsGet(final HttpResponsePacket response, - final HttpTxContext ctx) { + private boolean sendAsGet(final HttpResponsePacket response, final HttpTxContext ctx) { final int statusCode = response.getStatus(); - return !(statusCode < 302 || statusCode > 303) - && !(statusCode == 302 - && ctx.getProvider().getClientConfig().isStrict302Handling()); + return !(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && ctx.getProvider().getClientConfig().isStrict302Handling()); } } // END RedirectHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/StatusHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/StatusHandler.java index 5e2ec5d0cc..bca0d2a26f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/StatusHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/StatusHandler.java @@ -20,14 +20,10 @@ public interface StatusHandler { public enum InvocationStatus { - CONTINUE, - STOP + CONTINUE, STOP } - boolean handleStatus(final HttpResponsePacket httpResponse, - final HttpTxContext httpTransactionContext, - final FilterChainContext ctx); + boolean handleStatus(final HttpResponsePacket httpResponse, final HttpTxContext httpTransactionContext, final FilterChainContext ctx); boolean handlesStatus(final int statusCode); - } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java index 931d53f2ed..1a2f2122b2 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java @@ -33,9 +33,7 @@ final class AHCWebSocketListenerAdapter implements org.glassfish.grizzly.websock // -------------------------------------------------------- Constructors - - public AHCWebSocketListenerAdapter(final WebSocketListener ahcListener, - final GrizzlyWebSocketAdapter webSocket) { + public AHCWebSocketListenerAdapter(final WebSocketListener ahcListener, final GrizzlyWebSocketAdapter webSocket) { this.ahcListener = ahcListener; this.webSocket = webSocket; if (webSocket.bufferFragments) { @@ -47,10 +45,8 @@ public AHCWebSocketListenerAdapter(final WebSocketListener ahcListener, } } - // ------------------------------ Methods from Grizzly WebSocketListener - @Override public void onClose(org.glassfish.grizzly.websockets.WebSocket gWebSocket, DataFrame dataFrame) { try { @@ -168,8 +164,10 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byt @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; AHCWebSocketListenerAdapter that = (AHCWebSocketListenerAdapter) o; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java index 03cc157e4a..8374e89ab8 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java @@ -26,17 +26,13 @@ public final class GrizzlyWebSocketAdapter implements WebSocket { // -------------------------------------------------------- Constructors - - public GrizzlyWebSocketAdapter(final SimpleWebSocket gWebSocket, - final boolean bufferFragments) { + public GrizzlyWebSocketAdapter(final SimpleWebSocket gWebSocket, final boolean bufferFragments) { this.gWebSocket = gWebSocket; this.bufferFragments = bufferFragments; } - // ---------------------------------------------- Methods from AHC WebSocket - @Override public WebSocket sendMessage(byte[] message) { gWebSocket.send(message); @@ -105,10 +101,8 @@ public void close() { gWebSocket.close(); } - // ---------------------------------------------------------- Public Methods - public SimpleWebSocket getGrizzlyWebSocket() { return gWebSocket; } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncProviderBasicTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncProviderBasicTest.java index 3cb7ca2028..3c9403e205 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncProviderBasicTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncProviderBasicTest.java @@ -37,5 +37,4 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { protected String acceptEncodingHeader() { return "gzip"; } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamHandlerTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamHandlerTest.java index 3e2c4953fa..5f4dfd49b2 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamHandlerTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamHandlerTest.java @@ -23,5 +23,4 @@ public class GrizzlyAsyncStreamHandlerTest extends AsyncStreamHandlerTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamLifecycleTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamLifecycleTest.java index 9b705611a9..cee8d596dc 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamLifecycleTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncStreamLifecycleTest.java @@ -23,5 +23,4 @@ public class GrizzlyAsyncStreamLifecycleTest extends AsyncStreamLifecycleTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAuthTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAuthTimeoutTest.java index 81a62f933c..32dd918065 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAuthTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAuthTimeoutTest.java @@ -19,10 +19,8 @@ public class GrizzlyAuthTimeoutTest extends AuthTimeoutTest { - @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java index d0e761d800..08387273ae 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBasicAuthTest.java @@ -28,5 +28,4 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { public String getProviderClass() { return GrizzlyAsyncHttpProvider.class.getName(); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBodyChunkTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBodyChunkTest.java index 2fa8d6ddb8..782d973081 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBodyChunkTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyBodyChunkTest.java @@ -23,5 +23,4 @@ public class GrizzlyBodyChunkTest extends BodyChunkTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyByteBufferCapacityTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyByteBufferCapacityTest.java index a5eecc63da..3151f436ec 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyByteBufferCapacityTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyByteBufferCapacityTest.java @@ -25,7 +25,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - @Test(groups = {"standalone", "default_provider"}, enabled=false) + @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicByteBufferTest() throws Exception { } } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyChunkingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyChunkingTest.java index 904d17d509..eb20e31ab4 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyChunkingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyChunkingTest.java @@ -23,5 +23,4 @@ public class GrizzlyChunkingTest extends ChunkingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyComplexClientTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyComplexClientTest.java index 8ef3813c5a..4385eeb3ab 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyComplexClientTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyComplexClientTest.java @@ -23,5 +23,4 @@ public class GrizzlyComplexClientTest extends ComplexClientTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java index a1c365f437..1beb63e76e 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java @@ -33,14 +33,15 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { } @Override - @Test(enabled=false) + @Test(enabled = false) public void testMaxTotalConnectionsException() { } @Override @Test public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000) + .setMaximumConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyDigestAuthTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyDigestAuthTest.java index f6e3435933..ab5c9b9010 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyDigestAuthTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyDigestAuthTest.java @@ -23,5 +23,4 @@ public class GrizzlyDigestAuthTest extends DigestAuthTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyEmptyBodyTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyEmptyBodyTest.java index 161eeb2603..58cd22bd20 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyEmptyBodyTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyEmptyBodyTest.java @@ -23,5 +23,4 @@ public class GrizzlyEmptyBodyTest extends EmptyBodyTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyErrorResponseTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyErrorResponseTest.java index c8946c34b9..a3f52b8276 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyErrorResponseTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyErrorResponseTest.java @@ -23,5 +23,4 @@ public class GrizzlyErrorResponseTest extends ErrorResponseTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyExpectContinue100Test.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyExpectContinue100Test.java index b58e1a7021..fe1f7cff13 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyExpectContinue100Test.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyExpectContinue100Test.java @@ -17,11 +17,10 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.async.Expect100ContinueTest; -public class GrizzlyExpectContinue100Test extends Expect100ContinueTest{ +public class GrizzlyExpectContinue100Test extends Expect100ContinueTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFilterTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFilterTest.java index fd138b590d..b45f00a311 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFilterTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFilterTest.java @@ -23,5 +23,4 @@ public class GrizzlyFilterTest extends FilterTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFollowingThreadTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFollowingThreadTest.java index 2e602fa670..4f3c803611 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFollowingThreadTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFollowingThreadTest.java @@ -23,5 +23,4 @@ public class GrizzlyFollowingThreadTest extends FollowingThreadTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHead302Test.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHead302Test.java index d9975af031..af3f92b7dc 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHead302Test.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHead302Test.java @@ -23,5 +23,4 @@ public class GrizzlyHead302Test extends Head302Test { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHostnameVerifierTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHostnameVerifierTest.java index 8bc8df9a7d..7453f6a248 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHostnameVerifierTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHostnameVerifierTest.java @@ -23,5 +23,4 @@ public class GrizzlyHostnameVerifierTest extends HostnameVerifierTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHttpToHttpsRedirectTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHttpToHttpsRedirectTest.java index 6ac2d1083a..bd14ab34b4 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHttpToHttpsRedirectTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyHttpToHttpsRedirectTest.java @@ -23,5 +23,4 @@ public class GrizzlyHttpToHttpsRedirectTest extends HttpToHttpsRedirectTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyIdleStateHandlerTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyIdleStateHandlerTest.java index 395c489b3a..adc6a16410 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyIdleStateHandlerTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyIdleStateHandlerTest.java @@ -23,5 +23,4 @@ public class GrizzlyIdleStateHandlerTest extends IdleStateHandlerTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyInputStreamTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyInputStreamTest.java index b71ade1dfb..60503e83c3 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyInputStreamTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyInputStreamTest.java @@ -23,5 +23,4 @@ public class GrizzlyInputStreamTest extends InputStreamTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyListenableFutureTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyListenableFutureTest.java index bdfec6d848..866a09729a 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyListenableFutureTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyListenableFutureTest.java @@ -23,5 +23,4 @@ public class GrizzlyListenableFutureTest extends ListenableFutureTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMaxConnectionsInThreadsTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMaxConnectionsInThreadsTest.java index 70872b6a61..f07f7abfef 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMaxConnectionsInThreadsTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMaxConnectionsInThreadsTest.java @@ -26,7 +26,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { } @Override - @Test(enabled=false) + @Test(enabled = false) public void testMaxConnectionsWithinThreads() { super.testMaxConnectionsWithinThreads(); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMultipleHeaderTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMultipleHeaderTest.java index e0ceb7ac7a..3cf5965762 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMultipleHeaderTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyMultipleHeaderTest.java @@ -23,5 +23,4 @@ public class GrizzlyMultipleHeaderTest extends MultipleHeaderTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoNullResponseTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoNullResponseTest.java index cb38a7a42f..3dfe5a9354 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoNullResponseTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoNullResponseTest.java @@ -23,5 +23,4 @@ public class GrizzlyNoNullResponseTest extends NoNullResponseTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNonAsciiContentLengthTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNonAsciiContentLengthTest.java index 08a2c51717..7534360a33 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNonAsciiContentLengthTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNonAsciiContentLengthTest.java @@ -23,5 +23,4 @@ public class GrizzlyNonAsciiContentLengthTest extends NonAsciiContentLengthTest public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyParamEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyParamEncodingTest.java index dad25f32c6..c49beec010 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyParamEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyParamEncodingTest.java @@ -23,5 +23,4 @@ public class GrizzlyParamEncodingTest extends ParamEncodingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestRelative302Test.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestRelative302Test.java index 0ae732dd25..9f7aa9797e 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestRelative302Test.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestRelative302Test.java @@ -23,5 +23,4 @@ public class GrizzlyPerRequestRelative302Test extends PerRequestRelative302Test public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestTimeoutTest.java index d56f5f3cc9..14bccfc9d0 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPerRequestTimeoutTest.java @@ -30,5 +30,4 @@ protected void checkTimeoutMessage(String message) { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPostWithQSTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPostWithQSTest.java index 975f6e0b38..70f67cfc7d 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPostWithQSTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPostWithQSTest.java @@ -23,5 +23,4 @@ public class GrizzlyPostWithQSTest extends PostWithQSTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTest.java index ed024c917d..f3e1deab47 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTest.java @@ -23,5 +23,4 @@ public class GrizzlyProxyTest extends ProxyTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTunnelingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTunnelingTest.java index 434cda5730..1828989c4e 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTunnelingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProxyTunnelingTest.java @@ -26,6 +26,6 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override public String getProviderClass() { - return GrizzlyAsyncHttpProvider.class.getName(); + return GrizzlyAsyncHttpProvider.class.getName(); } } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPutLargeFileTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPutLargeFileTest.java index 89a52e4f6e..a3c3bfd6b7 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPutLargeFileTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyPutLargeFileTest.java @@ -23,5 +23,4 @@ public class GrizzlyPutLargeFileTest extends PutLargeFileTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyQueryParametersTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyQueryParametersTest.java index 5c57f83230..36ad0a8d50 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyQueryParametersTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyQueryParametersTest.java @@ -17,11 +17,10 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.async.QueryParametersTest; -public class GrizzlyQueryParametersTest extends QueryParametersTest{ +public class GrizzlyQueryParametersTest extends QueryParametersTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRelative302Test.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRelative302Test.java index 9157550248..6b0dffe2ca 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRelative302Test.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRelative302Test.java @@ -23,5 +23,4 @@ public class GrizzlyRelative302Test extends Relative302Test { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRemoteSiteTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRemoteSiteTest.java index 3b0126d932..cdfa5455f3 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRemoteSiteTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRemoteSiteTest.java @@ -23,5 +23,4 @@ public class GrizzlyRemoteSiteTest extends RemoteSiteTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRetryRequestTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRetryRequestTest.java index 37cb4fe2e5..8f27e132b1 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRetryRequestTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyRetryRequestTest.java @@ -23,5 +23,4 @@ public class GrizzlyRetryRequestTest extends RetryRequestTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyTransferListenerTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyTransferListenerTest.java index 59e24152c3..6173dbab41 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyTransferListenerTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyTransferListenerTest.java @@ -23,5 +23,4 @@ public class GrizzlyTransferListenerTest extends TransferListenerTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java index c6b05085ef..743255d00b 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -58,7 +58,8 @@ public AbstractHandler configureHandler() throws Exception { } private class ExpectExceptionHandler 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_UNAUTHORIZED); final Continuation continuation = ContinuationSupport.getContinuation(request); continuation.suspend(); From aea1dc9e4ee5993adcd1dbfdf2f2f847676e1b6b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 5 Mar 2014 23:11:01 +0100 Subject: [PATCH 0015/2070] Remove WTF import --- api/src/main/java/org/asynchttpclient/AsyncHttpClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java index 8a2f58294d..395b4ce1fd 100755 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java @@ -22,7 +22,6 @@ import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.multipart.Part; import org.asynchttpclient.resumable.ResumableAsyncHandler; -import org.eclipse.jetty.http.HttpContent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 576d657a2b3364c43ab1a0fe22a96af4322b1d1c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 5 Mar 2014 23:54:19 +0100 Subject: [PATCH 0016/2070] Disable microsoft.com based tests, see #496 --- .../asynchttpclient/async/RemoteSiteTest.java | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index 2954a4bbd4..521ce1d6bc 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -74,7 +74,8 @@ public void testMailGoogleCom() throws Exception { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) + // FIXME public void testMicrosoftCom() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { @@ -86,7 +87,8 @@ public void testMicrosoftCom() throws Exception { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) + // FIXME public void testWwwMicrosoftCom() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { @@ -98,7 +100,8 @@ public void testWwwMicrosoftCom() throws Exception { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) + // FIXME public void testUpdateMicrosoftCom() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { @@ -151,8 +154,8 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Exception { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirects(true).setAllowPoolingConnection(false) - .setMaximumNumberOfRedirects(6).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirects(true) + .setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { @@ -231,7 +234,8 @@ public void stripQueryStringTest() throws Exception { @Test(groups = { "online", "default_provider" }) public void stripQueryStringNegativeTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirects(true) + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); @@ -266,35 +270,36 @@ public void evilCoookieTest() throws Exception { public void testAHC62Com() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); try { - Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { + Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js") + .execute(new AsyncHandler() { - private Response.ResponseBuilder builder = new Response.ResponseBuilder(); + private Response.ResponseBuilder builder = new Response.ResponseBuilder(); - public void onThrowable(Throwable t) { - t.printStackTrace(); - } + public void onThrowable(Throwable t) { + t.printStackTrace(); + } - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - System.out.println(bodyPart.getBodyPartBytes().length); - builder.accumulate(bodyPart); + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + System.out.println(bodyPart.getBodyPartBytes().length); + builder.accumulate(bodyPart); - return STATE.CONTINUE; - } + return STATE.CONTINUE; + } - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - builder.accumulate(responseStatus); - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + builder.accumulate(responseStatus); + return STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - builder.accumulate(headers); - return STATE.CONTINUE; - } + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + builder.accumulate(headers); + return STATE.CONTINUE; + } - public Response onCompleted() throws Exception { - return builder.build(); - } - }).get(10, TimeUnit.SECONDS); + public Response onCompleted() throws Exception { + return builder.build(); + } + }).get(10, TimeUnit.SECONDS); assertNotNull(response); assertTrue(response.getResponseBody().length() >= 3870); } finally { From 36dd80381192b2fe58fb27bc8f3a3c8a601830de Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 6 Mar 2014 00:00:21 +0100 Subject: [PATCH 0017/2070] Fix javadoc --- api/src/main/java/org/asynchttpclient/AsyncHttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java index 395b4ce1fd..aa29c709f5 100755 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java @@ -122,8 +122,8 @@ *

* String bodyResponse = f.get(); *

* This class can also be used without the need of {@link AsyncHandler}

*

From 95886648512e99cc5e8501a10835e89e5d0ce253 Mon Sep 17 00:00:00 2001
From: Stephane Landelle 
Date: Thu, 6 Mar 2014 00:41:33 +0100
Subject: [PATCH 0018/2070] Turn AsyncHttpClient into an interface, close #497

---
 .../org/asynchttpclient/AsyncHttpClient.java  | 424 +-----------------
 .../asynchttpclient/BoundRequestBuilder.java  | 158 +++++++
 .../DefaultAsyncHttpClient.java               | 321 +++++++++++++
 .../SimpleAsyncHttpClient.java                |   4 +-
 .../async/AuthTimeoutTest.java                |   3 +-
 .../asynchttpclient/async/BasicAuthTest.java  |   5 +-
 .../async/BodyDeferringAsyncHandlerTest.java  |  11 +-
 .../async/MultipartUploadTest.java            |   2 +-
 .../async/NoNullResponseTest.java             |   2 +-
 .../async/NonAsciiContentLengthTest.java      |   2 +-
 .../extra/AsyncHttpDeferredObject.java        |   2 +-
 .../asynchttpclient/extra/AsyncHttpTest.java  |   5 +-
 .../grizzly/GrizzlyProviderUtil.java          |   3 +-
 .../providers/netty/NettyProviderUtil.java    |   3 +-
 14 files changed, 524 insertions(+), 421 deletions(-)
 create mode 100644 api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
 create mode 100644 api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java

diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java
index aa29c709f5..45136c2971 100755
--- a/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java
+++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClient.java
@@ -16,25 +16,9 @@
  */
 package org.asynchttpclient;
 
-import org.asynchttpclient.cookie.Cookie;
-import org.asynchttpclient.filter.FilterContext;
-import org.asynchttpclient.filter.FilterException;
-import org.asynchttpclient.filter.RequestFilter;
-import org.asynchttpclient.multipart.Part;
-import org.asynchttpclient.resumable.ResumableAsyncHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 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;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This class support asynchronous and synchronous HTTP request.
@@ -122,8 +106,8 @@
  * 

* String bodyResponse = f.get(); *

* This class can also be used without the need of {@link AsyncHandler}

*
@@ -142,300 +126,43 @@
  * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeoutInMs()}
  * expires. This object can hold many persistent connections to different host.
  */
-public class AsyncHttpClient implements Closeable {
-
-    /**
-     * Providers that will be searched for, on the classpath, in order when no
-     * provider is explicitly specified by the developer.
-     */
-    private static final String[] DEFAULT_PROVIDERS = {//
-    "org.asynchttpclient.providers.netty.NettyAsyncHttpProvider",/**/
-    "org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider"//
-    };
-
-    private final AsyncHttpProvider httpProvider;
-    private final AsyncHttpClientConfig config;
-    private final static Logger logger = LoggerFactory.getLogger(AsyncHttpClient.class);
-    private final AtomicBoolean isClosed = new AtomicBoolean(false);
-
-    /**
-     * Default signature calculator to use for all requests constructed by this client instance.
-     *
-     * @since 1.1
-     */
-    protected SignatureCalculator signatureCalculator;
-
-    /**
-     * Create a new HTTP Asynchronous Client using the default {@link AsyncHttpClientConfig} configuration. The
-     * default {@link AsyncHttpProvider} that will be used will be based on the classpath configuration.
-     *
-     * The default providers will be searched for in this order:
-     * 
    - *
  • netty
  • - *
  • grizzly
  • - *
- * - * If none of those providers are found, then the engine will throw an IllegalStateException. - */ - public AsyncHttpClient() { - this(new AsyncHttpClientConfig.Builder().build()); - } - - /** - * Create a new HTTP Asynchronous Client using an implementation of {@link AsyncHttpProvider} and - * the default {@link AsyncHttpClientConfig} configuration. - * - * @param provider a {@link AsyncHttpProvider} - */ - public AsyncHttpClient(AsyncHttpProvider provider) { - this(provider, new AsyncHttpClientConfig.Builder().build()); - } - - /** - * Create a new HTTP Asynchronous Client using the specified {@link AsyncHttpClientConfig} configuration. - * This configuration will be passed to the default {@link AsyncHttpProvider} that will be selected based on - * the classpath configuration. - * - * The default providers will be searched for in this order: - *
    - *
  • netty
  • - *
  • grizzly
  • - *
- * - * If none of those providers are found, then the engine will throw an IllegalStateException. - * - * @param config a {@link AsyncHttpClientConfig} - */ - public AsyncHttpClient(AsyncHttpClientConfig config) { - this(loadDefaultProvider(DEFAULT_PROVIDERS, config), config); - } - - /** - * Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and - * and a AsyncHttpProvider class' name. - * - * @param config a {@link AsyncHttpClientConfig} - * @param providerClass a {@link AsyncHttpProvider} - */ - public AsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { - this(loadProvider(providerClass, config), new AsyncHttpClientConfig.Builder().build()); - } - - /** - * Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and - * and a {@link AsyncHttpProvider}. - * - * @param config a {@link AsyncHttpClientConfig} - * @param httpProvider a {@link AsyncHttpProvider} - */ - public AsyncHttpClient(AsyncHttpProvider httpProvider, AsyncHttpClientConfig config) { - this.config = config; - this.httpProvider = httpProvider; - } - - 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); - } - - private BoundRequestBuilder(Request prototype) { - super(BoundRequestBuilder.class, prototype); - } - - public ListenableFuture execute(AsyncHandler handler) throws IOException { - return AsyncHttpClient.this.executeRequest(build(), handler); - } - - public ListenableFuture execute() throws IOException { - return AsyncHttpClient.this.executeRequest(build(), new AsyncCompletionHandlerBase()); - } - - // 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 - - @Override - public BoundRequestBuilder addBodyPart(Part part) { - return super.addBodyPart(part); - } - - @Override - public BoundRequestBuilder addCookie(Cookie cookie) { - return super.addCookie(cookie); - } - - @Override - public BoundRequestBuilder addHeader(String name, String value) { - return super.addHeader(name, value); - } - - @Override - public BoundRequestBuilder addParameter(String key, String value) { - return super.addParameter(key, value); - } - - @Override - public BoundRequestBuilder addQueryParameter(String name, String value) { - return super.addQueryParameter(name, 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(); - } - - @Override - public BoundRequestBuilder setBody(byte[] data) { - return super.setBody(data); - } - - @Override - public BoundRequestBuilder setBody(InputStream stream) { - return super.setBody(stream); - } - - @Override - public BoundRequestBuilder setBody(String data) { - return super.setBody(data); - } - - @Override - public BoundRequestBuilder setHeader(String name, String value) { - return super.setHeader(name, value); - } - - @Override - public BoundRequestBuilder setHeaders(FluentCaseInsensitiveStringsMap headers) { - return super.setHeaders(headers); - } - - @Override - public BoundRequestBuilder setHeaders(Map> headers) { - return super.setHeaders(headers); - } - - @Override - public BoundRequestBuilder setParameters(Map> parameters) { - return super.setParameters(parameters); - } - - @Override - public BoundRequestBuilder setParameters(FluentStringsMap parameters) { - return super.setParameters(parameters); - } - - @Override - public BoundRequestBuilder setUrl(String url) { - baseURL = url; - return super.setUrl(url); - } - - @Override - public BoundRequestBuilder setVirtualHost(String virtualHost) { - return super.setVirtualHost(virtualHost); - } - - public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureCalculator) { - this.signatureCalculator = signatureCalculator; - return this; - } - } +public interface AsyncHttpClient extends Closeable { /** * Return the asynchronous {@link AsyncHttpProvider} * * @return an {@link AsyncHttpProvider} */ - public AsyncHttpProvider getProvider() { - return httpProvider; - } + AsyncHttpProvider getProvider(); /** * Close the underlying connections. */ - public void close() { - if (isClosed.compareAndSet(false, true)) - httpProvider.close(); - } + void close(); /** * Asynchronous close the {@link AsyncHttpProvider} by spawning a thread and avoid blocking. */ - 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(); - } - } - }); - } - - @Override - protected void finalize() throws Throwable { - try { - if (!isClosed.get()) { - logger.error("AsyncHttpClient.close() hasn't been invoked, which may produce file descriptor leaks"); - } - } finally { - super.finalize(); - } - } + void closeAsynchronously(); /** * Return true if closed * * @return true if closed */ - public boolean isClosed() { - return isClosed.get(); - } + boolean isClosed(); /** * Return the {@link AsyncHttpClientConfig} * * @return {@link AsyncHttpClientConfig} */ - public AsyncHttpClientConfig getConfig() { - return config; - } + AsyncHttpClientConfig getConfig(); /** * Set default signature calculator to use for requests build by this client instance */ - public AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) { - this.signatureCalculator = signatureCalculator; - return this; - } + AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator); /** * Prepare an HTTP client GET request. @@ -443,9 +170,7 @@ public AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalcu * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareGet(String url) { - return requestBuilder("GET", url); - } + BoundRequestBuilder prepareGet(String url); /** * Prepare an HTTP client CONNECT request. @@ -453,9 +178,7 @@ public BoundRequestBuilder prepareGet(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareConnect(String url) { - return requestBuilder("CONNECT", url); - } + BoundRequestBuilder prepareConnect(String url); /** * Prepare an HTTP client OPTIONS request. @@ -463,9 +186,7 @@ public BoundRequestBuilder prepareConnect(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareOptions(String url) { - return requestBuilder("OPTIONS", url); - } + BoundRequestBuilder prepareOptions(String url); /** * Prepare an HTTP client HEAD request. @@ -473,9 +194,7 @@ public BoundRequestBuilder prepareOptions(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareHead(String url) { - return requestBuilder("HEAD", url); - } + BoundRequestBuilder prepareHead(String url); /** * Prepare an HTTP client POST request. @@ -483,9 +202,7 @@ public BoundRequestBuilder prepareHead(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder preparePost(String url) { - return requestBuilder("POST", url); - } + BoundRequestBuilder preparePost(String url); /** * Prepare an HTTP client PUT request. @@ -493,9 +210,7 @@ public BoundRequestBuilder preparePost(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder preparePut(String url) { - return requestBuilder("PUT", url); - } + BoundRequestBuilder preparePut(String url); /** * Prepare an HTTP client DELETE request. @@ -503,9 +218,7 @@ public BoundRequestBuilder preparePut(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareDelete(String url) { - return requestBuilder("DELETE", url); - } + BoundRequestBuilder prepareDelete(String url); /** * Prepare an HTTP client PATCH request. @@ -513,9 +226,7 @@ public BoundRequestBuilder prepareDelete(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder preparePatch(String url) { - return requestBuilder("PATCH", url); - } + BoundRequestBuilder preparePatch(String url); /** * Prepare an HTTP client TRACE request. @@ -523,9 +234,7 @@ public BoundRequestBuilder preparePatch(String url) { * @param url A well formed URL. * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareTrace(String url) { - return requestBuilder("TRACE", url); - } + BoundRequestBuilder prepareTrace(String url); /** * Construct a {@link RequestBuilder} using a {@link Request} @@ -533,9 +242,7 @@ public BoundRequestBuilder prepareTrace(String url) { * @param request a {@link Request} * @return {@link RequestBuilder} */ - public BoundRequestBuilder prepareRequest(Request request) { - return requestBuilder(request); - } + BoundRequestBuilder prepareRequest(Request request); /** * Execute an HTTP request. @@ -546,13 +253,7 @@ public BoundRequestBuilder prepareRequest(Request request) { * @return a {@link Future} of type T * @throws IOException */ - 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()); - } + ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException; /** * Execute an HTTP request. @@ -561,88 +262,5 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h * @return a {@link Future} of type Response * @throws IOException */ - 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()); - } - - /** - * Configure and execute the associated {@link RequestFilter}. This class may decorate the {@link Request} and {@link AsyncHandler} - * - * @param fc {@link FilterContext} - * @return {@link FilterContext} - */ - private FilterContext preProcessRequest(FilterContext fc) throws IOException { - 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; - } - } - - Request request = fc.getRequest(); - if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) { - request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request); - } - - if (request.getRangeOffset() != 0) { - RequestBuilder builder = new RequestBuilder(request); - builder.setHeader("Range", "bytes=" + request.getRangeOffset() + "-"); - request = builder.build(); - } - fc = new FilterContext.FilterContextBuilder(fc).request(request).build(); - return fc; - } - - @SuppressWarnings("unchecked") - private static AsyncHttpProvider loadProvider(final String className, final AsyncHttpClientConfig config) { - try { - Class providerClass = (Class) Thread.currentThread().getContextClassLoader() - .loadClass(className); - return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(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) AsyncHttpClient.class.getClassLoader().loadClass( - className); - return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(config); - } catch (Throwable ignored) { - } - } - return null; - } - - private static AsyncHttpProvider loadDefaultProvider(String[] providerClassNames, AsyncHttpClientConfig config) { - AsyncHttpProvider provider; - for (final String className : providerClassNames) { - provider = loadProvider(className, config); - if (provider != null) { - return provider; - } - } - throw new IllegalStateException("No providers found on the classpath"); - } - - protected BoundRequestBuilder requestBuilder(String reqType, String url) { - return new BoundRequestBuilder(reqType, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); - } - - protected BoundRequestBuilder requestBuilder(Request prototype) { - return new BoundRequestBuilder(prototype).setSignatureCalculator(signatureCalculator); - } + ListenableFuture executeRequest(Request request) throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java new file mode 100644 index 0000000000..7dacfb6cd3 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java @@ -0,0 +1,158 @@ +/* + * 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 org.asynchttpclient; + +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Map; + +public class BoundRequestBuilder extends RequestBuilderBase { + + private final AsyncHttpClient client; + + /** + * 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; + + public BoundRequestBuilder(AsyncHttpClient client, String reqType, boolean useRawUrl) { + super(BoundRequestBuilder.class, reqType, useRawUrl); + this.client = client; + } + + public BoundRequestBuilder(AsyncHttpClient client, Request prototype) { + super(BoundRequestBuilder.class, prototype); + this.client = client; + } + + public ListenableFuture execute(AsyncHandler handler) throws IOException { + return client.executeRequest(build(), handler); + } + + public ListenableFuture execute() throws IOException { + return client.executeRequest(build(), new AsyncCompletionHandlerBase()); + } + + // 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 + + @Override + public BoundRequestBuilder addBodyPart(Part part) { + return super.addBodyPart(part); + } + + @Override + public BoundRequestBuilder addCookie(Cookie cookie) { + return super.addCookie(cookie); + } + + @Override + public BoundRequestBuilder addHeader(String name, String value) { + return super.addHeader(name, value); + } + + @Override + public BoundRequestBuilder addParameter(String key, String value) { + return super.addParameter(key, value); + } + + @Override + public BoundRequestBuilder addQueryParameter(String name, String value) { + return super.addQueryParameter(name, 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(); + } + + @Override + public BoundRequestBuilder setBody(byte[] data) { + return super.setBody(data); + } + + @Override + public BoundRequestBuilder setBody(InputStream stream) { + return super.setBody(stream); + } + + @Override + public BoundRequestBuilder setBody(String data) { + return super.setBody(data); + } + + @Override + public BoundRequestBuilder setHeader(String name, String value) { + return super.setHeader(name, value); + } + + @Override + public BoundRequestBuilder setHeaders(FluentCaseInsensitiveStringsMap headers) { + return super.setHeaders(headers); + } + + @Override + public BoundRequestBuilder setHeaders(Map> headers) { + return super.setHeaders(headers); + } + + @Override + public BoundRequestBuilder setParameters(Map> parameters) { + return super.setParameters(parameters); + } + + @Override + public BoundRequestBuilder setParameters(FluentStringsMap parameters) { + return super.setParameters(parameters); + } + + @Override + public BoundRequestBuilder setUrl(String url) { + baseURL = url; + return super.setUrl(url); + } + + @Override + public BoundRequestBuilder setVirtualHost(String virtualHost) { + return super.setVirtualHost(virtualHost); + } + + public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureCalculator) { + this.signatureCalculator = signatureCalculator; + return this; + } +} \ No newline at end of file diff --git a/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java new file mode 100644 index 0000000000..4cb934af6b --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java @@ -0,0 +1,321 @@ +/* + * 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 org.asynchttpclient; + +import org.asynchttpclient.filter.FilterContext; +import org.asynchttpclient.filter.FilterException; +import org.asynchttpclient.filter.RequestFilter; +import org.asynchttpclient.resumable.ResumableAsyncHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +public class DefaultAsyncHttpClient implements AsyncHttpClient { + + /** + * Providers that will be searched for, on the classpath, in order when no + * provider is explicitly specified by the developer. + */ + private static final String[] DEFAULT_PROVIDERS = {// + "org.asynchttpclient.providers.netty.NettyAsyncHttpProvider",/**/ + "org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider"// + }; + + private final AsyncHttpProvider httpProvider; + private final AsyncHttpClientConfig config; + private final static Logger logger = LoggerFactory.getLogger(DefaultAsyncHttpClient.class); + private final AtomicBoolean isClosed = new AtomicBoolean(false); + + /** + * Default signature calculator to use for all requests constructed by this client instance. + * + * @since 1.1 + */ + protected SignatureCalculator signatureCalculator; + + /** + * Create a new HTTP Asynchronous Client using the default {@link AsyncHttpClientConfig} configuration. The + * default {@link AsyncHttpProvider} that will be used will be based on the classpath configuration. + * + * The default providers will be searched for in this order: + *
    + *
  • netty
  • + *
  • grizzly
  • + *
+ * + * If none of those providers are found, then the engine will throw an IllegalStateException. + */ + public DefaultAsyncHttpClient() { + this(new AsyncHttpClientConfig.Builder().build()); + } + + /** + * Create a new HTTP Asynchronous Client using an implementation of {@link AsyncHttpProvider} and + * the default {@link AsyncHttpClientConfig} configuration. + * + * @param provider a {@link AsyncHttpProvider} + */ + public DefaultAsyncHttpClient(AsyncHttpProvider provider) { + this(provider, new AsyncHttpClientConfig.Builder().build()); + } + + /** + * Create a new HTTP Asynchronous Client using the specified {@link AsyncHttpClientConfig} configuration. + * This configuration will be passed to the default {@link AsyncHttpProvider} that will be selected based on + * the classpath configuration. + * + * The default providers will be searched for in this order: + *
    + *
  • netty
  • + *
  • grizzly
  • + *
+ * + * If none of those providers are found, then the engine will throw an IllegalStateException. + * + * @param config a {@link AsyncHttpClientConfig} + */ + public DefaultAsyncHttpClient(AsyncHttpClientConfig config) { + this(loadDefaultProvider(DEFAULT_PROVIDERS, config), config); + } + + /** + * Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and + * and a AsyncHttpProvider class' name. + * + * @param config a {@link AsyncHttpClientConfig} + * @param providerClass a {@link AsyncHttpProvider} + */ + public DefaultAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { + this(loadProvider(providerClass, config), new AsyncHttpClientConfig.Builder().build()); + } + + /** + * Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and + * and a {@link AsyncHttpProvider}. + * + * @param config a {@link AsyncHttpClientConfig} + * @param httpProvider a {@link AsyncHttpProvider} + */ + public DefaultAsyncHttpClient(AsyncHttpProvider httpProvider, AsyncHttpClientConfig config) { + this.config = config; + this.httpProvider = httpProvider; + } + + @Override + public AsyncHttpProvider getProvider() { + return httpProvider; + } + + @Override + public void close() { + if (isClosed.compareAndSet(false, true)) + httpProvider.close(); + } + + @Override + 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(); + } + } + }); + } + + @Override + protected void finalize() throws Throwable { + try { + if (!isClosed.get()) { + logger.error("AsyncHttpClient.close() hasn't been invoked, which may produce file descriptor leaks"); + } + } finally { + super.finalize(); + } + } + + @Override + public boolean isClosed() { + return isClosed.get(); + } + + @Override + public AsyncHttpClientConfig getConfig() { + return config; + } + + @Override + public DefaultAsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) { + this.signatureCalculator = signatureCalculator; + return this; + } + + @Override + public BoundRequestBuilder prepareGet(String url) { + return requestBuilder("GET", url); + } + + @Override + public BoundRequestBuilder prepareConnect(String url) { + return requestBuilder("CONNECT", url); + } + + @Override + public BoundRequestBuilder prepareOptions(String url) { + return requestBuilder("OPTIONS", url); + } + + @Override + public BoundRequestBuilder prepareHead(String url) { + return requestBuilder("HEAD", url); + } + + @Override + public BoundRequestBuilder preparePost(String url) { + return requestBuilder("POST", url); + } + + @Override + public BoundRequestBuilder preparePut(String url) { + return requestBuilder("PUT", url); + } + + @Override + public BoundRequestBuilder prepareDelete(String url) { + return requestBuilder("DELETE", url); + } + + @Override + public BoundRequestBuilder preparePatch(String url) { + return requestBuilder("PATCH", url); + } + + @Override + public BoundRequestBuilder prepareTrace(String url) { + return requestBuilder("TRACE", url); + } + + @Override + public BoundRequestBuilder prepareRequest(Request request) { + return requestBuilder(request); + } + + @Override + 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()); + } + + @Override + 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()); + } + + /** + * Configure and execute the associated {@link RequestFilter}. This class may decorate the {@link Request} and {@link AsyncHandler} + * + * @param fc {@link FilterContext} + * @return {@link FilterContext} + */ + private FilterContext preProcessRequest(FilterContext fc) throws IOException { + 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; + } + } + + Request request = fc.getRequest(); + if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) { + request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request); + } + + if (request.getRangeOffset() != 0) { + RequestBuilder builder = new RequestBuilder(request); + builder.setHeader("Range", "bytes=" + request.getRangeOffset() + "-"); + request = builder.build(); + } + fc = new FilterContext.FilterContextBuilder(fc).request(request).build(); + return fc; + } + + @SuppressWarnings("unchecked") + private static AsyncHttpProvider loadProvider(final String className, final AsyncHttpClientConfig config) { + try { + Class providerClass = (Class) Thread.currentThread().getContextClassLoader() + .loadClass(className); + return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(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) DefaultAsyncHttpClient.class.getClassLoader().loadClass( + className); + return providerClass.getDeclaredConstructor(new Class[] { AsyncHttpClientConfig.class }).newInstance(config); + } catch (Throwable ignored) { + } + } + return null; + } + + private static AsyncHttpProvider loadDefaultProvider(String[] providerClassNames, AsyncHttpClientConfig config) { + AsyncHttpProvider provider; + for (final String className : providerClassNames) { + provider = loadProvider(className, config); + if (provider != null) { + return provider; + } + } + throw new IllegalStateException("No providers found on the classpath"); + } + + protected BoundRequestBuilder requestBuilder(String reqType, String url) { + return new BoundRequestBuilder(this, reqType, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); + } + + protected BoundRequestBuilder requestBuilder(Request prototype) { + return new BoundRequestBuilder(this, prototype).setSignatureCalculator(signatureCalculator); + } +} diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 3764f520ab..271a352ed6 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -298,9 +298,9 @@ private AsyncHttpClient asyncHttpClient() { synchronized (config) { if (asyncHttpClient == null) { if (providerClass == null) - asyncHttpClient = new AsyncHttpClient(config); + asyncHttpClient = new DefaultAsyncHttpClient(config); else - asyncHttpClient = new AsyncHttpClient(providerClass, config); + asyncHttpClient = new DefaultAsyncHttpClient(providerClass, config); } } return asyncHttpClient; diff --git a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java index 6edbf58fcb..cb532d74a9 100644 --- a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java @@ -24,6 +24,7 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.Realm; import org.asynchttpclient.Response; import org.asynchttpclient.util.AsyncHttpProviderUtils; @@ -214,7 +215,7 @@ private AsyncHttpClient newClient() { } protected Future execute(AsyncHttpClient client, Server server, boolean preemptive) throws IOException { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm(realm(preemptive)).setHeader("X-Content", "Test"); + BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm(realm(preemptive)).setHeader("X-Content", "Test"); Future f = r.execute(); return f; } diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 541d7bd4b5..144556d9da 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -29,6 +29,7 @@ import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; @@ -201,7 +202,7 @@ public void redirectAndBasicAuthTest() throws Exception, ExecutionException, Tim public void basic401Test() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl())// + BoundRequestBuilder r = client.prepareGet(getTargetUrl())// .setHeader("X-401", "401")// .setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).build()); @@ -374,7 +375,7 @@ public void stringBuilderBodyConsumerTest() throws Exception { public void noneAuthTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).build()); + BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).build()); Future f = r.execute(); Response resp = f.get(3, TimeUnit.SECONDS); diff --git a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java index 0f21806b9d..2b7c26ee16 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java @@ -24,6 +24,7 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.BodyDeferringAsyncHandler; import org.asynchttpclient.BodyDeferringAsyncHandler.BodyDeferringInputStream; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -115,7 +116,7 @@ public AsyncHttpClientConfig getAsyncHttpClientConfig() { public void deferredSimple() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimple"); + BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimple"); CountingOutputStream cos = new CountingOutputStream(); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); @@ -142,7 +143,7 @@ public void deferredSimple() throws IOException, ExecutionException, TimeoutExce public void deferredSimpleWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimpleWithFailure").addHeader("X-FAIL-TRANSFER", + BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimpleWithFailure").addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); CountingOutputStream cos = new CountingOutputStream(); @@ -175,7 +176,7 @@ public void deferredSimpleWithFailure() throws IOException, ExecutionException, public void deferredInputStreamTrick() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrick"); + BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrick"); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); @@ -212,7 +213,7 @@ public void deferredInputStreamTrickWithFailure() throws IOException, ExecutionE AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrickWithFailure").addHeader("X-FAIL-TRANSFER", + BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrickWithFailure").addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); @@ -249,7 +250,7 @@ public void testConnectionRefused() throws IOException, ExecutionException, Time int newPortWithoutAnyoneListening = findFreePort(); AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + newPortWithoutAnyoneListening + "/testConnectionRefused"); + BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + newPortWithoutAnyoneListening + "/testConnectionRefused"); CountingOutputStream cos = new CountingOutputStream(); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); diff --git a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java index fc173e856b..cbf13877de 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java @@ -168,7 +168,7 @@ public void testSendingSmallFilesAndByteArray() { bc.setFollowRedirects(true); - AsyncHttpClient c = new AsyncHttpClient(bc.build()); + AsyncHttpClient c = getAsyncHttpClient(bc.build()); try { diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 363c7cbbec..01411d9906 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -19,8 +19,8 @@ import static org.testng.Assert.assertNotNull; import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.Response; import org.testng.annotations.Test; diff --git a/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java b/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java index 937f607e3c..b47b52394e 100644 --- a/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NonAsciiContentLengthTest.java @@ -17,7 +17,7 @@ import static org.testng.Assert.assertEquals; import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.Response; import org.asynchttpclient.util.StandardCharsets; import org.eclipse.jetty.server.Request; diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java index 5763048d0a..7be6007aa0 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java @@ -17,7 +17,7 @@ import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClient.BoundRequestBuilder; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.Response; import org.jdeferred.Promise; diff --git a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java index de50435835..0d5eeb837b 100644 --- a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java +++ b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java @@ -19,6 +19,7 @@ import static org.testng.Assert.assertTrue; import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.DefaultAsyncHttpClient; import org.asynchttpclient.Response; import org.jdeferred.DoneCallback; import org.jdeferred.ProgressCallback; @@ -38,7 +39,7 @@ public void testPromiseAdapter() throws IOException { final AtomicInteger successCount = new AtomicInteger(); final AtomicInteger progressCount = new AtomicInteger(); - AsyncHttpClient client = new AsyncHttpClient(); + AsyncHttpClient client = new DefaultAsyncHttpClient(); try { Promise p1 = AsyncHttpDeferredObject.promise(client.prepareGet("http://www.ning.com/")); @@ -73,7 +74,7 @@ public void testMultiplePromiseAdapter() throws IOException { final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger successCount = new AtomicInteger(); - AsyncHttpClient client = new AsyncHttpClient(); + AsyncHttpClient client = new DefaultAsyncHttpClient(); try { Promise p1 = AsyncHttpDeferredObject.promise(client.prepareGet("http://www.ning.com/")); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java index 83368e7892..501eb0ff7a 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyProviderUtil.java @@ -17,6 +17,7 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.DefaultAsyncHttpClient; public class GrizzlyProviderUtil { @@ -24,6 +25,6 @@ public static AsyncHttpClient grizzlyProvider(AsyncHttpClientConfig config) { if (config == null) { config = new AsyncHttpClientConfig.Builder().build(); } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); } } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProviderUtil.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProviderUtil.java index 983076d728..b6120976bf 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProviderUtil.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyProviderUtil.java @@ -17,6 +17,7 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.DefaultAsyncHttpClient; public class NettyProviderUtil { @@ -24,6 +25,6 @@ public static AsyncHttpClient nettyProvider(AsyncHttpClientConfig config) { if (config == null) { config = new AsyncHttpClientConfig.Builder().build(); } - return new AsyncHttpClient(new NettyAsyncHttpProvider(config), config); + return new DefaultAsyncHttpClient(new NettyAsyncHttpProvider(config), config); } } From dde23768f66354c245baee829d65ed390bb0cfd9 Mon Sep 17 00:00:00 2001 From: Dale Date: Tue, 11 Mar 2014 15:04:01 +0000 Subject: [PATCH 0019/2070] Fix a minor typo in a comment --- api/src/main/java/org/asynchttpclient/RequestBuilderBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index e9b6081bd0..810e102483 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -618,7 +618,7 @@ public Request build() { try { request.length = Long.parseLong(contentLength); } catch (NumberFormatException e) { - // NoOp -- we wdn't specify length so it will be chunked? + // NoOp -- we won't specify length so it will be chunked? } } } From 77bf3be1893ed4dee6cf815cbb16c1cb219bbbba Mon Sep 17 00:00:00 2001 From: Roger Schildmeijer Date: Thu, 13 Mar 2014 13:41:46 +0100 Subject: [PATCH 0020/2070] Make the fairness semantics of the ThrottleRequestFilter configurable --- .../org/asynchttpclient/extra/ThrottleRequestFilter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java index 7445af3eec..c554ea7453 100644 --- a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java +++ b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java @@ -35,8 +35,12 @@ public ThrottleRequestFilter(int maxConnections) { } public ThrottleRequestFilter(int maxConnections, int maxWait) { - this.maxWait = maxWait; - available = new Semaphore(maxConnections, true); + this(maxConnections, maxWait, true); + } + + public ThrottleRequestFilter(int maxConnections, int maxWait, boolean fair) { + this.maxWait = maxWait; + available = new Semaphore(maxConnections, fair); } /** From 3df41bf45f3eb6db02a722ffeef97796f5f1ce47 Mon Sep 17 00:00:00 2001 From: Roger Schildmeijer Date: Thu, 13 Mar 2014 14:36:26 +0100 Subject: [PATCH 0021/2070] Default to unfair locking semantics for the ThrottleRequestFilter --- .../java/org/asynchttpclient/extra/ThrottleRequestFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java index c554ea7453..7dd44d34a1 100644 --- a/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java +++ b/api/src/main/java/org/asynchttpclient/extra/ThrottleRequestFilter.java @@ -35,7 +35,7 @@ public ThrottleRequestFilter(int maxConnections) { } public ThrottleRequestFilter(int maxConnections, int maxWait) { - this(maxConnections, maxWait, true); + this(maxConnections, maxWait, false); } public ThrottleRequestFilter(int maxConnections, int maxWait, boolean fair) { From 90b561ed3665016cca94a06913cfebd594e7d670 Mon Sep 17 00:00:00 2001 From: sasurendran Date: Fri, 14 Mar 2014 21:41:41 -0700 Subject: [PATCH 0022/2070] Adding AsyncHttpClientFactory and AsyncHttpClientRegistry --- README.md | 12 +- .../AsyncHttpClientFactory.java | 128 +++++++++ .../AsyncHttpClientImplException.java | 13 + .../AsyncHttpClientRegistry.java | 70 +++++ .../AsyncHttpClientRegistryImpl.java | 111 ++++++++ .../asynchttpclient/util/AsyncImplHelper.java | 98 +++++++ .../AbstractAsyncHttpClientFactoryTest.java | 248 ++++++++++++++++++ .../AsyncHttpClientRegistryTest.java | 103 ++++++++ .../asynchttpclient/BadAsyncHttpClient.java | 118 +++++++++ .../BadAsyncHttpClientException.java | 9 + .../BadAsyncHttpClientRegistry.java | 9 + .../asynchttpclient/TestAsyncHttpClient.java | 116 ++++++++ .../TestAsyncHttpClientRegistry.java | 5 + pom.xml | 6 + .../GrizzlyAsyncHttpClientFactoryTest.java | 19 ++ .../NettyAsyncHttpClientFactoryTest.java | 19 ++ 16 files changed, 1078 insertions(+), 6 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java create mode 100644 api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java create mode 100644 api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java create mode 100644 api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java create mode 100644 api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java create mode 100644 api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java create mode 100644 api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java create mode 100644 api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java create mode 100644 api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java create mode 100644 api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java create mode 100644 api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java create mode 100644 api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java create mode 100644 providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java create mode 100644 providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java diff --git a/README.md b/README.md index ebd1fb6b13..392fc4a005 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Then in your code you can simply do ([Javadoc](http://sonatype.github.com/async- import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); +AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); Future f = asyncHttpClient.prepareGet("http://www.ning.com/").execute(); Response r = f.get(); ``` @@ -37,7 +37,7 @@ You can also accomplish asynchronous (non-blocking) operation without using a Fu import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); +AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); asyncHttpClient.prepareGet("http://www.ning.com/").execute(new AsyncCompletionHandler(){ @Override @@ -62,7 +62,7 @@ You can also mix Future with AsyncHandler to only retrieve part of the asynchron import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); +AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); Future f = asyncHttpClient.prepareGet("http://www.ning.com/").execute( new AsyncCompletionHandler(){ @@ -89,7 +89,7 @@ which is something you want to do for large responses: this way you can process import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient c = new AsyncHttpClient(); +AsyncHttpClient c = AsyncHttpClientFactory.getAsyncHttpClient(); Future f = c.prepareGet("http://www.ning.com/").execute(new AsyncHandler() { private ByteArrayOutputStream bytes = new ByteArrayOutputStream(); @@ -140,7 +140,7 @@ Finally, you can also configure the AsyncHttpClient via its AsyncHttpClientConfi ```java AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder() S.setProxyServer(new ProxyServer("127.0.0.1", 38080)).build(); -AsyncHttpClient c = new AsyncHttpClient(cf); +AsyncHttpClient c = AsyncHttpClientFactory.getAsyncHttpClient(cf); ``` ## WebSocket @@ -176,7 +176,7 @@ The library uses Java non blocking I/O for supporting asynchronous operations. T ```java AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); -AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); +AsyncHttpClient client = AsyncHttpClientFactory.getAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); ``` ## User Group diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java new file mode 100644 index 0000000000..7efb7200b1 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java @@ -0,0 +1,128 @@ +package org.asynchttpclient; + +import org.asynchttpclient.util.AsyncImplHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * The AsyncHttpClientFactory returns back an instance of AsyncHttpClient. The + * actual instance is determined by the system property + * 'org.async.http.client.impl'. If the system property doesn't exist then it + * checks for a property file 'asynchttpclient.properties' and looks for a + * property 'org.async.http.client.impl' in there. If it finds it then returns + * an instance of that class. If there is an exception while reading the + * properties file or system property it throws a RuntimeException + * AsyncHttpClientImplException. If any of the constructors of the instance + * throws an exception it thows a AsyncHttpClientImplException. By default if + * neither the system property or the property file exists then it will return + * the default instance of {@link DefaultAsyncHttpClient} + * + * @author sasurendran + * + */ +public class AsyncHttpClientFactory { + + private static Class asyncHttpClientImplClass = null; + private static volatile boolean instantiated = false; + public static final Logger logger = LoggerFactory.getLogger(AsyncHttpClientFactory.class); + private static Lock lock = new ReentrantLock(); + + public static AsyncHttpClient getAsyncHttpClient() { + + try { + if (attemptInstantiation()) + return (AsyncHttpClient) asyncHttpClientImplClass.newInstance(); + } catch (InstantiationException e) { + throw new AsyncHttpClientImplException("Unable to create the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY,e); + } catch (IllegalAccessException e) { + throw new AsyncHttpClientImplException("Unable to find the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY,e); + } + return new DefaultAsyncHttpClient(); + } + + public static AsyncHttpClient getAsyncHttpClient(AsyncHttpProvider provider) { + if (attemptInstantiation()) { + try { + Constructor constructor = asyncHttpClientImplClass + .getConstructor(AsyncHttpProvider.class); + return constructor.newInstance(provider); + }catch (Exception e) { + throw new AsyncHttpClientImplException( + "Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + } + } + return new DefaultAsyncHttpClient(provider); + } + + public static AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + if (attemptInstantiation()) { + try { + Constructor constructor = asyncHttpClientImplClass + .getConstructor(AsyncHttpClientConfig.class); + return constructor.newInstance(config); + } catch (Exception e) { + throw new AsyncHttpClientImplException( + "Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + } + } + return new DefaultAsyncHttpClient(config); + } + + public static AsyncHttpClient getAsyncHttpClient(AsyncHttpProvider provider, AsyncHttpClientConfig config) { + if (attemptInstantiation()) { + try { + Constructor constructor = asyncHttpClientImplClass.getConstructor( + AsyncHttpProvider.class, AsyncHttpClientConfig.class); + return constructor.newInstance(provider, config); + } catch (Exception e) { + throw new AsyncHttpClientImplException( + "Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + } + } + return new DefaultAsyncHttpClient(provider, config); + } + + public static AsyncHttpClient getAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { + if (attemptInstantiation()) { + try { + Constructor constructor = asyncHttpClientImplClass.getConstructor(String.class, + AsyncHttpClientConfig.class); + return constructor.newInstance(providerClass, config); + } catch (Exception e) { + throw new AsyncHttpClientImplException( + "Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + } + } + return new DefaultAsyncHttpClient(providerClass, config); + } + + private static boolean attemptInstantiation() { + if (!instantiated) { + lock.lock(); + try { + if (!instantiated) { + asyncHttpClientImplClass = AsyncImplHelper + .getAsyncImplClass(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY); + instantiated = true; + } + } finally { + lock.unlock(); + } + } + return asyncHttpClientImplClass != null; + } +} diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java new file mode 100644 index 0000000000..9917029e1a --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java @@ -0,0 +1,13 @@ +package org.asynchttpclient; + +public class AsyncHttpClientImplException extends RuntimeException { + + public AsyncHttpClientImplException(String msg) { + super(msg); + } + + public AsyncHttpClientImplException(String msg, Exception e) { + super(msg, e); + } + +} diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java new file mode 100644 index 0000000000..59bc54416f --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java @@ -0,0 +1,70 @@ +package org.asynchttpclient; + +import java.util.Set; + +public interface AsyncHttpClientRegistry { + + /** + * Returns back the AsyncHttpClient associated with this name + * + * @param clientName + * @return + */ + AsyncHttpClient get(String clientName); + + /** + * Registers this instance of AsyncHttpClient with this name and returns + * back a null if an instance with the same name never existed but will return back the + * previous instance if there was another instance registered with the same + * name and has been replaced by this one. + * + * @param name + * @param ahc + * @return + */ + AsyncHttpClient addOrReplace(String name, AsyncHttpClient ahc); + + /** + * Will register only if an instance with this name doesn't exist and if it + * does exist will not replace this instance and will return false. Use it in the + * following way: + *
+     *      AsyncHttpClient ahc = AsyncHttpClientFactory.getAsyncHttpClient();      
+     *      if(!AsyncHttpClientRegistryImpl.getInstance().registerIfNew(“MyAHC”,ahc)){
+     *          //An instance with this name is already registered so close ahc 
+     *          ahc.close(); 
+     *          //and do necessary cleanup
+     *      }
+     * 
+ * + * @param name + * @param ahc + * @return + */ + + boolean registerIfNew(String name, AsyncHttpClient ahc); + + /** + * Remove the instance associate with this name + * + * @param name + * @return + */ + + boolean unRegister(String name); + + /** + * Returns back all registered names + * + * @return + */ + + Set getAllRegisteredNames(); + + /** + * Removes all instances from this registry. + */ + + void clearAllInstances(); + +} \ No newline at end of file diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java new file mode 100644 index 0000000000..ec006c62a8 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java @@ -0,0 +1,111 @@ +package org.asynchttpclient; + +import org.asynchttpclient.util.AsyncImplHelper; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class AsyncHttpClientRegistryImpl implements AsyncHttpClientRegistry { + + private static ConcurrentMap asyncHttpClientMap = new ConcurrentHashMap(); + private static volatile AsyncHttpClientRegistry _instance; + private static Lock lock = new ReentrantLock(); + + /** + * Returns a singleton instance of AsyncHttpClientRegistry + * @return + */ + public static AsyncHttpClientRegistry getInstance() { + if (_instance == null) { + lock.lock(); + try { + if (_instance == null) { + Class asyncHttpClientRegistryImplClass = AsyncImplHelper + .getAsyncImplClass(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY); + if (asyncHttpClientRegistryImplClass != null) + _instance = (AsyncHttpClientRegistry) asyncHttpClientRegistryImplClass.newInstance(); + else + _instance = new AsyncHttpClientRegistryImpl(); + } + } catch (InstantiationException e) { + throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " + + e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " + + e.getMessage(), e); + } finally { + lock.unlock(); + } + } + return _instance; + } + + /* + * (non-Javadoc) + * + * @see org.asynchttpclient.IAsyncHttpClientRegistry#get(java.lang.String) + */ + @Override + public AsyncHttpClient get(String clientName) { + return asyncHttpClientMap.get(clientName); + } + + /* + * (non-Javadoc) + * + * @see + * org.asynchttpclient.IAsyncHttpClientRegistry#register(java.lang.String, + * org.asynchttpclient.AsyncHttpClient) + */ + @Override + public AsyncHttpClient addOrReplace(String name, AsyncHttpClient ahc) { + return asyncHttpClientMap.put(name, ahc); + } + + /* + * (non-Javadoc) + * + * @see + * org.asynchttpclient.IAsyncHttpClientRegistry#registerIfNew(java.lang. + * String, org.asynchttpclient.AsyncHttpClient) + */ + @Override + public boolean registerIfNew(String name, AsyncHttpClient ahc) { + return asyncHttpClientMap.putIfAbsent(name, ahc)==null; + } + + /* + * (non-Javadoc) + * + * @see + * org.asynchttpclient.IAsyncHttpClientRegistry#unRegister(java.lang.String) + */ + @Override + public boolean unRegister(String name) { + return asyncHttpClientMap.remove(name) != null; + } + + /* + * (non-Javadoc) + * + * @see org.asynchttpclient.IAsyncHttpClientRegistry#getAllRegisteredNames() + */ + @Override + public Set getAllRegisteredNames() { + return asyncHttpClientMap.keySet(); + } + + /* + * (non-Javadoc) + * + * @see org.asynchttpclient.IAsyncHttpClientRegistry#clearAllInstances() + */ + @Override + public void clearAllInstances() { + asyncHttpClientMap.clear(); + } + +} diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java new file mode 100644 index 0000000000..a432b408fe --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java @@ -0,0 +1,98 @@ +package org.asynchttpclient.util; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientFactory; +import org.asynchttpclient.AsyncHttpClientImplException; + +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Properties; + +public class AsyncImplHelper { + + private static String getSystemProperty(final String systemProperty) { + return AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(systemProperty); + } + }); + } + + /* + * Returns the class specified by either a system property or a properties + * file as the class to instantiated for the AsyncHttpClient. Returns null + * if property is not found and throws an AsyncHttpClientImplException if + * the specified class couldn't be created. + */ + public static Class getAsyncImplClass(String propertyName) { + String asyncHttpClientImplClassName = getSystemProperty(propertyName); + if (asyncHttpClientImplClassName == null) { + Properties properties = AsyncImplHelper.getAsyncImplProperties(); + if (properties != null) + asyncHttpClientImplClassName = properties.getProperty(propertyName); + } + + if (asyncHttpClientImplClassName == null) + return null; + + Class asyncHttpClientImplClass = AsyncImplHelper.getClass(asyncHttpClientImplClassName); + return asyncHttpClientImplClass; + } + + private static Properties getAsyncImplProperties() { + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Properties run() throws IOException { + InputStream stream = null; + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl != null) + stream = cl.getResourceAsStream(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_PROPERTIES_FILE); + if (stream == null) + stream = ClassLoader.getSystemClassLoader().getResourceAsStream( + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_PROPERTIES_FILE); + if (stream != null) { + Properties properties = new Properties(); + properties.load(stream); + return properties; + } + return null; + } + }); + } catch (PrivilegedActionException e) { + throw new AsyncHttpClientImplException("Unable to read properties file because of exception : " + + e.getMessage(), e); + } + } + + private static Class getClass(final String asyncImplClassName) { + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction>() { + public Class run() throws ClassNotFoundException { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl != null) + try { + return cl.loadClass(asyncImplClassName); + } catch (ClassNotFoundException e) { + AsyncHttpClientFactory.logger.info("Couldn't find class : " + asyncImplClassName + + " in thread context classpath " + "checking system class path next",e); + } + + cl = ClassLoader.getSystemClassLoader(); + return cl.loadClass(asyncImplClassName); + } + }); + } catch (PrivilegedActionException e) { + throw new AsyncHttpClientImplException("Class : " + asyncImplClassName + " couldn't be found in " + + " the classpath due to : " + e.getMessage(), e); + } + } + + public static final String ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY = "org.async.http.client.impl"; + public static final String ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY = "org.async.http.client.registry.impl"; + public static final String ASYNC_HTTP_CLIENT_IMPL_PROPERTIES_FILE = "asynchttpclient.properties"; + +} diff --git a/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java b/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java new file mode 100644 index 0000000000..f144738ef5 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java @@ -0,0 +1,248 @@ +package org.asynchttpclient; + +import org.asynchttpclient.async.util.EchoHandler; +import org.asynchttpclient.async.util.TestUtils; +import org.asynchttpclient.util.AsyncImplHelper; +import org.eclipse.jetty.server.Server; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.lang.reflect.InvocationTargetException; +import junit.extensions.PA; + + +public abstract class AbstractAsyncHttpClientFactoryTest { + + private Server server; + private int port; + + @BeforeMethod + public void setUp() { + PA.setValue(AsyncHttpClientFactory.class, "instantiated", false); + PA.setValue(AsyncHttpClientFactory.class, "asyncHttpClientImplClass", null); + System.clearProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY); + } + + @BeforeClass(alwaysRun = true) + public void setUpBeforeTest() throws Exception { + port = TestUtils.findFreePort(); + server = TestUtils.newJettyHttpServer(port); + server.setHandler(new EchoHandler()); + server.start(); + } + + @AfterClass(alwaysRun = true) + public void tearDown() throws Exception { + setUp(); + if (server != null) + server.stop(); + } + + public abstract AsyncHttpProvider getAsyncHttpProvider(AsyncHttpClientConfig config); + + /** + * If the property is not found via the system property or properties file + * the default instance of AsyncHttpClient should be returned. + */ + // ================================================================================================================ + @Test(groups = "fast") + public void testGetAsyncHttpClient() { + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); + assertClientWorks(asyncHttpClient); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfig() { + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); + assertClientWorks(asyncHttpClient); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientProvider() { + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); + Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); + assertClientWorks(asyncHttpClient); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfigAndProvider() { + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), + new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); + assertClientWorks(asyncHttpClient); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientStringConfig() { + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), + new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); + assertClientWorks(asyncHttpClient); + } + + // ================================================================================================================================== + + /** + * If the class is specified via a system property then that class should be + * returned + */ + // =================================================================================================================================== + @Test(groups = "fast") + public void testFactoryWithSystemProperty() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + Assert.assertTrue(AsyncHttpClientFactory.getAsyncHttpClient().getClass().equals(TestAsyncHttpClient.class)); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfigWithSystemProperty() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientProviderWithSystemProperty() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); + Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfigAndProviderWithSystemProperty() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), + new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientStringConfigWithSystemProperty() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), + new AsyncHttpClientConfig.Builder().build()); + Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); + } + + // =================================================================================================================================== + + /** + * If any of the constructors of the class fail then a + * AsyncHttpClientException is thrown. + */ + // =================================================================================================================================== + @Test(groups = "fast", expectedExceptions = BadAsyncHttpClientException.class) + public void testFactoryWithBadAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.fail("BadAsyncHttpClientException should have been thrown before this point"); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfigWithBadAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + try{ + AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + }catch(AsyncHttpClientImplException e){ + assertException(e); + } + //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); + } + + + + @Test(groups = "fast") + public void testGetAsyncHttpClientProviderWithBadAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + try{ + AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); + }catch(AsyncHttpClientImplException e){ + assertException(e); + } + //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientConfigAndProviderWithBadAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + try{ + AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), new AsyncHttpClientConfig.Builder().build()); + }catch(AsyncHttpClientImplException e){ + assertException(e); + } + //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); + } + + @Test(groups = "fast") + public void testGetAsyncHttpClientStringConfigWithBadAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + try{ + AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), + new AsyncHttpClientConfig.Builder().build()); + }catch(AsyncHttpClientImplException e){ + assertException(e); + } + //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); + } + + // =================================================================================================================================== + + /* + * If the system property exists instantiate the class else if the class is + * not found throw an AsyncHttpClientException. + */ + @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) + public void testFactoryWithNonExistentAsyncHttpClient() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncHttpClient"); + AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); + } + + /** + * If property is specified but the class can’t be created or found for any + * reason subsequent calls should throw an AsyncClientException. + */ + @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) + public void testRepeatedCallsToBadAsyncHttpClient() { + boolean exceptionCaught = false; + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncHttpClient"); + try { + AsyncHttpClientFactory.getAsyncHttpClient(); + } catch (AsyncHttpClientImplException e) { + exceptionCaught = true; + } + Assert.assertTrue(exceptionCaught,"Didn't catch exception the first time"); + exceptionCaught = false; + try { + AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + } catch (AsyncHttpClientImplException e) { + exceptionCaught = true; + } + Assert.assertTrue(exceptionCaught,"Didn't catch exception the second time"); + AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), + new AsyncHttpClientConfig.Builder().build()); + + } + + private void assertClientWorks(AsyncHttpClient asyncHttpClient){ + Response response; + try { + response = asyncHttpClient.prepareGet("http://localhost/" + port + "/foo/test").execute().get(); + Assert.assertEquals(200, response.getStatusCode()); + } catch (Exception e) { + Assert.fail("Failed while making call with AsyncHttpClient", e); + }finally{ + asyncHttpClient.close(); + } + } + + private void assertException(AsyncHttpClientImplException e) { + InvocationTargetException t = (InvocationTargetException)e.getCause(); + Assert.assertTrue(t.getCause().getClass().equals(BadAsyncHttpClientException.class)); + } + +} diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java b/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java new file mode 100644 index 0000000000..ae01d6f191 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java @@ -0,0 +1,103 @@ +package org.asynchttpclient; + +import org.asynchttpclient.util.AsyncImplHelper; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import junit.extensions.PA; + +public class AsyncHttpClientRegistryTest { + + private static final String TEST_AHC = "testAhc"; + + @BeforeMethod + public void setUp() { + System.clearProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY); + AsyncHttpClientRegistryImpl.getInstance().clearAllInstances(); + PA.setValue(AsyncHttpClientRegistryImpl.class, "_instance", null); + } + + @BeforeClass + public void setUpBeforeTest() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, + "org.asynchttpclient.TestAsyncHttpClient"); + } + + @AfterClass + public void tearDown() { + System.clearProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY); + } + + @Test(groups = "fast") + public void testGetAndRegister() { + AsyncHttpClient ahc = AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC, ahc)); + Assert.assertNotNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC)); + } + + @Test(groups = "fast") + public void testDeRegister() { + AsyncHttpClient ahc = AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.assertFalse(AsyncHttpClientRegistryImpl.getInstance().unRegister(TEST_AHC)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC, ahc)); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance().unRegister(TEST_AHC)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC)); + } + + @Test(groups = "fast") + public void testRegisterIfNew() { + AsyncHttpClient ahc = AsyncHttpClientFactory.getAsyncHttpClient(); + AsyncHttpClient ahc2 = AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC, ahc)); + Assert.assertFalse(AsyncHttpClientRegistryImpl.getInstance().registerIfNew(TEST_AHC, ahc2)); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC) == ahc); + Assert.assertNotNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC, ahc2)); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC) == ahc2); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance().registerIfNew(TEST_AHC + 1, ahc)); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC + 1) == ahc); + } + + @Test(groups = "fast") + public void testClearAllInstances() { + AsyncHttpClient ahc = AsyncHttpClientFactory.getAsyncHttpClient(); + AsyncHttpClient ahc2 = AsyncHttpClientFactory.getAsyncHttpClient(); + AsyncHttpClient ahc3 = AsyncHttpClientFactory.getAsyncHttpClient(); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC, ahc)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC + 2, ahc2)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().addOrReplace(TEST_AHC + 3, ahc3)); + Assert.assertEquals(3, AsyncHttpClientRegistryImpl.getInstance().getAllRegisteredNames().size()); + AsyncHttpClientRegistryImpl.getInstance().clearAllInstances(); + Assert.assertEquals(0, AsyncHttpClientRegistryImpl.getInstance().getAllRegisteredNames().size()); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC + 2)); + Assert.assertNull(AsyncHttpClientRegistryImpl.getInstance().get(TEST_AHC + 3)); + } + + @Test(groups = "fast") + public void testCustomAsyncHttpClientRegistry() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, + TestAsyncHttpClientRegistry.class.getName()); + Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance() instanceof TestAsyncHttpClientRegistry); + } + + @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) + public void testNonExistentAsyncHttpClientRegistry() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, + "org.asynchttpclient.NonExistentAsyncRegistry"); + AsyncHttpClientRegistryImpl.getInstance(); + Assert.fail("Should never have reached here"); + } + + @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) + public void testBadAsyncHttpClientRegistry() { + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, + "org.asynchttpclient.BadAsyncHttpClientRegistry"); + AsyncHttpClientRegistryImpl.getInstance(); + Assert.fail("Should never have reached here"); + } + +} diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java new file mode 100644 index 0000000000..b04d75b28d --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java @@ -0,0 +1,118 @@ +package org.asynchttpclient; + +import java.io.IOException; + +public class BadAsyncHttpClient implements AsyncHttpClient { + + + public BadAsyncHttpClient() { + throw new BadAsyncHttpClientException("Because I am bad!!"); + } + + public BadAsyncHttpClient(AsyncHttpProvider provider) { + throw new BadAsyncHttpClientException("Because I am bad!!"); + } + + public BadAsyncHttpClient(AsyncHttpClientConfig config) { + throw new BadAsyncHttpClientException("Because I am bad!!"); + } + + public BadAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { + throw new BadAsyncHttpClientException("Because I am bad!!"); + } + + public BadAsyncHttpClient(AsyncHttpProvider httpProvider, AsyncHttpClientConfig config) { + throw new BadAsyncHttpClientException("Because I am bad!!"); + } + + @Override + public AsyncHttpProvider getProvider() { + return null; + } + + @Override + public void close() { + + } + + @Override + public void closeAsynchronously() { + + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public AsyncHttpClientConfig getConfig() { + return null; + } + + @Override + public AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) { + return null; + } + + @Override + public BoundRequestBuilder prepareGet(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareConnect(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareOptions(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareHead(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePost(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePut(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareDelete(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePatch(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareTrace(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareRequest(Request request) { + return null; + } + + @Override + public ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException { + return null; + } + + @Override + public ListenableFuture executeRequest(Request request) throws IOException { + return null; + } + +} diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java new file mode 100644 index 0000000000..fee176ff1e --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java @@ -0,0 +1,9 @@ +package org.asynchttpclient; + +public class BadAsyncHttpClientException extends AsyncHttpClientImplException { + + public BadAsyncHttpClientException(String msg) { + super(msg); + } + +} diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java new file mode 100644 index 0000000000..03911ca84a --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java @@ -0,0 +1,9 @@ +package org.asynchttpclient; + +public class BadAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { + + private BadAsyncHttpClientRegistry() { + throw new RuntimeException("I am bad"); + } + +} diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java new file mode 100644 index 0000000000..796abd71c4 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java @@ -0,0 +1,116 @@ +package org.asynchttpclient; + +import java.io.IOException; + +public class TestAsyncHttpClient implements AsyncHttpClient { + + public TestAsyncHttpClient() { + + } + + public TestAsyncHttpClient(AsyncHttpProvider provider) { + + } + + public TestAsyncHttpClient(AsyncHttpClientConfig config) { + + } + + public TestAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { + + } + + public TestAsyncHttpClient(AsyncHttpProvider httpProvider, AsyncHttpClientConfig config) { + } + + @Override + public AsyncHttpProvider getProvider() { + return null; + } + + @Override + public void close() { + + } + + @Override + public void closeAsynchronously() { + + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public AsyncHttpClientConfig getConfig() { + return null; + } + + @Override + public AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) { + return null; + } + + @Override + public BoundRequestBuilder prepareGet(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareConnect(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareOptions(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareHead(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePost(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePut(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareDelete(String url) { + return null; + } + + @Override + public BoundRequestBuilder preparePatch(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareTrace(String url) { + return null; + } + + @Override + public BoundRequestBuilder prepareRequest(Request request) { + return null; + } + + @Override + public ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException { + return null; + } + + @Override + public ListenableFuture executeRequest(Request request) throws IOException { + return null; + } + +} diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java new file mode 100644 index 0000000000..e1cf7797dc --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java @@ -0,0 +1,5 @@ +package org.asynchttpclient; + +public class TestAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { + +} diff --git a/pom.xml b/pom.xml index fe94209066..e1fc39bebf 100644 --- a/pom.xml +++ b/pom.xml @@ -513,6 +513,12 @@ ${commons-fileupload.version} test + + com.e-movimento.tinytools + privilegedaccessor + 1.2.2 + test + http://oss.sonatype.org/content/repositories/snapshots diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java new file mode 100644 index 0000000000..2ede2e88ac --- /dev/null +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java @@ -0,0 +1,19 @@ +package org.asynchttpclient.providers.grizzly; + +import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.testng.annotations.Test; + +@Test +public class GrizzlyAsyncHttpClientFactoryTest extends AbstractAsyncHttpClientFactoryTest { + + @Override + public AsyncHttpProvider getAsyncHttpProvider(AsyncHttpClientConfig config) { + if (config == null) { + config = new AsyncHttpClientConfig.Builder().build(); + } + return new GrizzlyAsyncHttpProvider(config); + } + +} diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java new file mode 100644 index 0000000000..b671564dad --- /dev/null +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java @@ -0,0 +1,19 @@ +package org.asynchttpclient.providers.netty; + +import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.testng.annotations.Test; + +@Test +public class NettyAsyncHttpClientFactoryTest extends AbstractAsyncHttpClientFactoryTest { + + @Override + public AsyncHttpProvider getAsyncHttpProvider(AsyncHttpClientConfig config) { + if (config == null) { + config = new AsyncHttpClientConfig.Builder().build(); + } + return new NettyAsyncHttpProvider(config); + } + +} From 3d84b363886af1550d69229e1bcbaf72720e5d5d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 15 Mar 2014 10:02:35 +0100 Subject: [PATCH 0023/2070] Revert back README changes as they can't be displayed as lon as AHC2 is not released --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 392fc4a005..ebd1fb6b13 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Then in your code you can simply do ([Javadoc](http://sonatype.github.com/async- import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); +AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); Future f = asyncHttpClient.prepareGet("http://www.ning.com/").execute(); Response r = f.get(); ``` @@ -37,7 +37,7 @@ You can also accomplish asynchronous (non-blocking) operation without using a Fu import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); +AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); asyncHttpClient.prepareGet("http://www.ning.com/").execute(new AsyncCompletionHandler(){ @Override @@ -62,7 +62,7 @@ You can also mix Future with AsyncHandler to only retrieve part of the asynchron import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); +AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); Future f = asyncHttpClient.prepareGet("http://www.ning.com/").execute( new AsyncCompletionHandler(){ @@ -89,7 +89,7 @@ which is something you want to do for large responses: this way you can process import com.ning.http.client.*; import java.util.concurrent.Future; -AsyncHttpClient c = AsyncHttpClientFactory.getAsyncHttpClient(); +AsyncHttpClient c = new AsyncHttpClient(); Future f = c.prepareGet("http://www.ning.com/").execute(new AsyncHandler() { private ByteArrayOutputStream bytes = new ByteArrayOutputStream(); @@ -140,7 +140,7 @@ Finally, you can also configure the AsyncHttpClient via its AsyncHttpClientConfi ```java AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder() S.setProxyServer(new ProxyServer("127.0.0.1", 38080)).build(); -AsyncHttpClient c = AsyncHttpClientFactory.getAsyncHttpClient(cf); +AsyncHttpClient c = new AsyncHttpClient(cf); ``` ## WebSocket @@ -176,7 +176,7 @@ The library uses Java non blocking I/O for supporting asynchronous operations. T ```java AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); -AsyncHttpClient client = AsyncHttpClientFactory.getAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); +AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); ``` ## User Group From 2a74af2b1272450f3af83d9834883f747adcb08d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 15 Mar 2014 10:19:51 +0100 Subject: [PATCH 0024/2070] Clean up after #498: license headers, format --- .../AsyncHttpClientFactory.java | 55 +++++++++-------- .../AsyncHttpClientImplException.java | 14 ++++- .../AsyncHttpClientRegistry.java | 19 ++++-- .../AsyncHttpClientRegistryImpl.java | 23 ++++--- .../asynchttpclient/util/AsyncImplHelper.java | 37 +++++++---- .../AbstractAsyncHttpClientFactoryTest.java | 61 +++++++++++-------- .../AsyncHttpClientRegistryTest.java | 24 +++++--- .../asynchttpclient/BadAsyncHttpClient.java | 15 ++++- .../BadAsyncHttpClientException.java | 14 ++++- .../BadAsyncHttpClientRegistry.java | 13 +++- .../asynchttpclient/TestAsyncHttpClient.java | 18 ++++-- .../TestAsyncHttpClientRegistry.java | 12 ++++ pom.xml | 3 +- .../GrizzlyAsyncHttpClientFactoryTest.java | 13 +++- .../NettyAsyncHttpClientFactoryTest.java | 13 +++- 15 files changed, 235 insertions(+), 99 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java index 7efb7200b1..8135f60163 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import org.asynchttpclient.util.AsyncImplHelper; @@ -38,10 +50,10 @@ public static AsyncHttpClient getAsyncHttpClient() { return (AsyncHttpClient) asyncHttpClientImplClass.newInstance(); } catch (InstantiationException e) { throw new AsyncHttpClientImplException("Unable to create the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY,e); + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, e); } catch (IllegalAccessException e) { throw new AsyncHttpClientImplException("Unable to find the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY,e); + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, e); } return new DefaultAsyncHttpClient(); } @@ -49,14 +61,11 @@ public static AsyncHttpClient getAsyncHttpClient() { public static AsyncHttpClient getAsyncHttpClient(AsyncHttpProvider provider) { if (attemptInstantiation()) { try { - Constructor constructor = asyncHttpClientImplClass - .getConstructor(AsyncHttpProvider.class); + Constructor constructor = asyncHttpClientImplClass.getConstructor(AsyncHttpProvider.class); return constructor.newInstance(provider); - }catch (Exception e) { - throw new AsyncHttpClientImplException( - "Unable to find the instantiate the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY - + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + } catch (Exception e) { + throw new AsyncHttpClientImplException("Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + "(AsyncHttpProvider) due to : " + e.getMessage(), e); } } return new DefaultAsyncHttpClient(provider); @@ -65,14 +74,11 @@ public static AsyncHttpClient getAsyncHttpClient(AsyncHttpProvider provider) { public static AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { if (attemptInstantiation()) { try { - Constructor constructor = asyncHttpClientImplClass - .getConstructor(AsyncHttpClientConfig.class); + Constructor constructor = asyncHttpClientImplClass.getConstructor(AsyncHttpClientConfig.class); return constructor.newInstance(config); } catch (Exception e) { - throw new AsyncHttpClientImplException( - "Unable to find the instantiate the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY - + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + throw new AsyncHttpClientImplException("Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + "(AsyncHttpProvider) due to : " + e.getMessage(), e); } } return new DefaultAsyncHttpClient(config); @@ -81,14 +87,12 @@ public static AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { public static AsyncHttpClient getAsyncHttpClient(AsyncHttpProvider provider, AsyncHttpClientConfig config) { if (attemptInstantiation()) { try { - Constructor constructor = asyncHttpClientImplClass.getConstructor( - AsyncHttpProvider.class, AsyncHttpClientConfig.class); + Constructor constructor = asyncHttpClientImplClass.getConstructor(AsyncHttpProvider.class, + AsyncHttpClientConfig.class); return constructor.newInstance(provider, config); } catch (Exception e) { - throw new AsyncHttpClientImplException( - "Unable to find the instantiate the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY - + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + throw new AsyncHttpClientImplException("Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + "(AsyncHttpProvider) due to : " + e.getMessage(), e); } } return new DefaultAsyncHttpClient(provider, config); @@ -101,10 +105,8 @@ public static AsyncHttpClient getAsyncHttpClient(String providerClass, AsyncHttp AsyncHttpClientConfig.class); return constructor.newInstance(providerClass, config); } catch (Exception e) { - throw new AsyncHttpClientImplException( - "Unable to find the instantiate the class specified by system property : " - + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY - + "(AsyncHttpProvider) due to : " + e.getMessage(), e); + throw new AsyncHttpClientImplException("Unable to find the instantiate the class specified by system property : " + + AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY + "(AsyncHttpProvider) due to : " + e.getMessage(), e); } } return new DefaultAsyncHttpClient(providerClass, config); @@ -115,8 +117,7 @@ private static boolean attemptInstantiation() { lock.lock(); try { if (!instantiated) { - asyncHttpClientImplClass = AsyncImplHelper - .getAsyncImplClass(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY); + asyncHttpClientImplClass = AsyncImplHelper.getAsyncImplClass(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY); instantiated = true; } } finally { diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java index 9917029e1a..08e75e90fd 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java @@ -1,5 +1,18 @@ +/* + * 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 org.asynchttpclient; +@SuppressWarnings("serial") public class AsyncHttpClientImplException extends RuntimeException { public AsyncHttpClientImplException(String msg) { @@ -9,5 +22,4 @@ public AsyncHttpClientImplException(String msg) { public AsyncHttpClientImplException(String msg, Exception e) { super(msg, e); } - } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java index 59bc54416f..740313380a 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import java.util.Set; @@ -58,13 +70,12 @@ public interface AsyncHttpClientRegistry { * * @return */ - + Set getAllRegisteredNames(); /** * Removes all instances from this registry. */ - - void clearAllInstances(); -} \ No newline at end of file + void clearAllInstances(); +} diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java index ec006c62a8..61d8f3d38a 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import org.asynchttpclient.util.AsyncImplHelper; @@ -23,7 +35,7 @@ public static AsyncHttpClientRegistry getInstance() { lock.lock(); try { if (_instance == null) { - Class asyncHttpClientRegistryImplClass = AsyncImplHelper + Class asyncHttpClientRegistryImplClass = AsyncImplHelper .getAsyncImplClass(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY); if (asyncHttpClientRegistryImplClass != null) _instance = (AsyncHttpClientRegistry) asyncHttpClientRegistryImplClass.newInstance(); @@ -31,11 +43,9 @@ public static AsyncHttpClientRegistry getInstance() { _instance = new AsyncHttpClientRegistryImpl(); } } catch (InstantiationException e) { - throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " - + e.getMessage(), e); + throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " + e.getMessage(), e); } catch (IllegalAccessException e) { - throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " - + e.getMessage(), e); + throw new AsyncHttpClientImplException("Couldn't instantiate AsyncHttpClientRegistry : " + e.getMessage(), e); } finally { lock.unlock(); } @@ -74,7 +84,7 @@ public AsyncHttpClient addOrReplace(String name, AsyncHttpClient ahc) { */ @Override public boolean registerIfNew(String name, AsyncHttpClient ahc) { - return asyncHttpClientMap.putIfAbsent(name, ahc)==null; + return asyncHttpClientMap.putIfAbsent(name, ahc) == null; } /* @@ -107,5 +117,4 @@ public Set getAllRegisteredNames() { public void clearAllInstances() { asyncHttpClientMap.clear(); } - } diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java index a432b408fe..a61d2d74d6 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.util; import org.asynchttpclient.AsyncHttpClient; @@ -14,6 +26,10 @@ public class AsyncImplHelper { + public static final String ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY = "org.async.http.client.impl"; + public static final String ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY = "org.async.http.client.registry.impl"; + public static final String ASYNC_HTTP_CLIENT_IMPL_PROPERTIES_FILE = "asynchttpclient.properties"; + private static String getSystemProperty(final String systemProperty) { return AccessController.doPrivileged(new PrivilegedAction() { public String run() { @@ -63,36 +79,31 @@ public Properties run() throws IOException { } }); } catch (PrivilegedActionException e) { - throw new AsyncHttpClientImplException("Unable to read properties file because of exception : " - + e.getMessage(), e); + throw new AsyncHttpClientImplException("Unable to read properties file because of exception : " + e.getMessage(), e); } } private static Class getClass(final String asyncImplClassName) { try { return AccessController.doPrivileged(new PrivilegedExceptionAction>() { - public Class run() throws ClassNotFoundException { + @SuppressWarnings("unchecked") + public Class run() throws ClassNotFoundException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl != null) try { - return cl.loadClass(asyncImplClassName); + return (Class) cl.loadClass(asyncImplClassName); } catch (ClassNotFoundException e) { AsyncHttpClientFactory.logger.info("Couldn't find class : " + asyncImplClassName - + " in thread context classpath " + "checking system class path next",e); + + " in thread context classpath " + "checking system class path next", e); } cl = ClassLoader.getSystemClassLoader(); - return cl.loadClass(asyncImplClassName); + return (Class) cl.loadClass(asyncImplClassName); } }); } catch (PrivilegedActionException e) { - throw new AsyncHttpClientImplException("Class : " + asyncImplClassName + " couldn't be found in " - + " the classpath due to : " + e.getMessage(), e); + throw new AsyncHttpClientImplException("Class : " + asyncImplClassName + " couldn't be found in " + " the classpath due to : " + + e.getMessage(), e); } } - - public static final String ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY = "org.async.http.client.impl"; - public static final String ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY = "org.async.http.client.registry.impl"; - public static final String ASYNC_HTTP_CLIENT_IMPL_PROPERTIES_FILE = "asynchttpclient.properties"; - } diff --git a/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java b/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java index f144738ef5..757c1c26d9 100644 --- a/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java +++ b/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import org.asynchttpclient.async.util.EchoHandler; @@ -13,7 +25,6 @@ import java.lang.reflect.InvocationTargetException; import junit.extensions.PA; - public abstract class AbstractAsyncHttpClientFactoryTest { private Server server; @@ -53,7 +64,7 @@ public void testGetAsyncHttpClient() { AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(); Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); assertClientWorks(asyncHttpClient); - } + } @Test(groups = "fast") public void testGetAsyncHttpClientConfig() { @@ -72,7 +83,7 @@ public void testGetAsyncHttpClientProvider() { @Test(groups = "fast") public void testGetAsyncHttpClientConfigAndProvider() { AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), - new AsyncHttpClientConfig.Builder().build()); + new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); assertClientWorks(asyncHttpClient); } @@ -80,7 +91,7 @@ public void testGetAsyncHttpClientConfigAndProvider() { @Test(groups = "fast") public void testGetAsyncHttpClientStringConfig() { AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), - new AsyncHttpClientConfig.Builder().build()); + new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(DefaultAsyncHttpClient.class)); assertClientWorks(asyncHttpClient); } @@ -116,7 +127,7 @@ public void testGetAsyncHttpClientProviderWithSystemProperty() { public void testGetAsyncHttpClientConfigAndProviderWithSystemProperty() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), - new AsyncHttpClientConfig.Builder().build()); + new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); } @@ -124,7 +135,7 @@ public void testGetAsyncHttpClientConfigAndProviderWithSystemProperty() { public void testGetAsyncHttpClientStringConfigWithSystemProperty() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), - new AsyncHttpClientConfig.Builder().build()); + new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); } @@ -145,22 +156,20 @@ public void testFactoryWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientConfigWithBadAsyncHttpClient() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); - try{ + try { AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - }catch(AsyncHttpClientImplException e){ + } catch (AsyncHttpClientImplException e) { assertException(e); } //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); } - - @Test(groups = "fast") public void testGetAsyncHttpClientProviderWithBadAsyncHttpClient() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); - try{ + try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); - }catch(AsyncHttpClientImplException e){ + } catch (AsyncHttpClientImplException e) { assertException(e); } //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); @@ -169,9 +178,9 @@ public void testGetAsyncHttpClientProviderWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientConfigAndProviderWithBadAsyncHttpClient() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); - try{ + try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), new AsyncHttpClientConfig.Builder().build()); - }catch(AsyncHttpClientImplException e){ + } catch (AsyncHttpClientImplException e) { assertException(e); } //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); @@ -180,10 +189,10 @@ public void testGetAsyncHttpClientConfigAndProviderWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientStringConfigWithBadAsyncHttpClient() { System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); - try{ + try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), - new AsyncHttpClientConfig.Builder().build()); - }catch(AsyncHttpClientImplException e){ + new AsyncHttpClientConfig.Builder().build()); + } catch (AsyncHttpClientImplException e) { assertException(e); } //Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); @@ -215,34 +224,34 @@ public void testRepeatedCallsToBadAsyncHttpClient() { } catch (AsyncHttpClientImplException e) { exceptionCaught = true; } - Assert.assertTrue(exceptionCaught,"Didn't catch exception the first time"); + Assert.assertTrue(exceptionCaught, "Didn't catch exception the first time"); exceptionCaught = false; try { AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); } catch (AsyncHttpClientImplException e) { exceptionCaught = true; } - Assert.assertTrue(exceptionCaught,"Didn't catch exception the second time"); + Assert.assertTrue(exceptionCaught, "Didn't catch exception the second time"); AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), - new AsyncHttpClientConfig.Builder().build()); + new AsyncHttpClientConfig.Builder().build()); } - - private void assertClientWorks(AsyncHttpClient asyncHttpClient){ + + private void assertClientWorks(AsyncHttpClient asyncHttpClient) { Response response; try { response = asyncHttpClient.prepareGet("http://localhost/" + port + "/foo/test").execute().get(); Assert.assertEquals(200, response.getStatusCode()); } catch (Exception e) { Assert.fail("Failed while making call with AsyncHttpClient", e); - }finally{ + } finally { asyncHttpClient.close(); } } - + private void assertException(AsyncHttpClientImplException e) { - InvocationTargetException t = (InvocationTargetException)e.getCause(); + InvocationTargetException t = (InvocationTargetException) e.getCause(); Assert.assertTrue(t.getCause().getClass().equals(BadAsyncHttpClientException.class)); - } + } } diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java b/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java index ae01d6f191..569c539308 100644 --- a/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java +++ b/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import org.asynchttpclient.util.AsyncImplHelper; @@ -22,8 +34,7 @@ public void setUp() { @BeforeClass public void setUpBeforeTest() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, - "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); } @AfterClass @@ -79,23 +90,20 @@ public void testClearAllInstances() { @Test(groups = "fast") public void testCustomAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, - TestAsyncHttpClientRegistry.class.getName()); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, TestAsyncHttpClientRegistry.class.getName()); Assert.assertTrue(AsyncHttpClientRegistryImpl.getInstance() instanceof TestAsyncHttpClientRegistry); } @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testNonExistentAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, - "org.asynchttpclient.NonExistentAsyncRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncRegistry"); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testBadAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, - "org.asynchttpclient.BadAsyncHttpClientRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClientRegistry"); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java index b04d75b28d..f8e72c9538 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java @@ -1,10 +1,21 @@ +/* + * 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 org.asynchttpclient; import java.io.IOException; public class BadAsyncHttpClient implements AsyncHttpClient { - - + public BadAsyncHttpClient() { throw new BadAsyncHttpClientException("Because I am bad!!"); } diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java index fee176ff1e..af384e8623 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java @@ -1,9 +1,21 @@ +/* + * 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 org.asynchttpclient; +@SuppressWarnings("serial") public class BadAsyncHttpClientException extends AsyncHttpClientImplException { public BadAsyncHttpClientException(String msg) { super(msg); } - } diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java index 03911ca84a..9ed9b5de88 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java +++ b/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; public class BadAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { @@ -5,5 +17,4 @@ public class BadAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { private BadAsyncHttpClientRegistry() { throw new RuntimeException("I am bad"); } - } diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java index 796abd71c4..1d9ab99702 100644 --- a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java +++ b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; import java.io.IOException; @@ -5,19 +17,15 @@ public class TestAsyncHttpClient implements AsyncHttpClient { public TestAsyncHttpClient() { - } public TestAsyncHttpClient(AsyncHttpProvider provider) { - } public TestAsyncHttpClient(AsyncHttpClientConfig config) { - } public TestAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { - } public TestAsyncHttpClient(AsyncHttpProvider httpProvider, AsyncHttpClientConfig config) { @@ -30,12 +38,10 @@ public AsyncHttpProvider getProvider() { @Override public void close() { - } @Override public void closeAsynchronously() { - } @Override diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java index e1cf7797dc..2f4ec9247e 100644 --- a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java +++ b/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient; public class TestAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { diff --git a/pom.xml b/pom.xml index e1fc39bebf..a4e54d8ded 100644 --- a/pom.xml +++ b/pom.xml @@ -516,7 +516,7 @@ com.e-movimento.tinytools privilegedaccessor - 1.2.2 + ${privilegedaccessor.version} test @@ -533,6 +533,7 @@ 6.0.29 2.4 1.3 + 1.2.2 diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java index 2ede2e88ac..e201b05a9d 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.providers.grizzly; import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; @@ -15,5 +27,4 @@ public AsyncHttpProvider getAsyncHttpProvider(AsyncHttpClientConfig config) { } return new GrizzlyAsyncHttpProvider(config); } - } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java index b671564dad..dc2d152b0f 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java @@ -1,3 +1,15 @@ +/* + * 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 org.asynchttpclient.providers.netty; import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; @@ -15,5 +27,4 @@ public AsyncHttpProvider getAsyncHttpProvider(AsyncHttpClientConfig config) { } return new NettyAsyncHttpProvider(config); } - } From db405942a7d19adcb8e5011ee2cfede3ecf22dfc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 15 Mar 2014 10:20:01 +0100 Subject: [PATCH 0025/2070] Upgrade slf4j 1.7.6 --- api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/pom.xml b/api/pom.xml index 78a6cba8d9..bf1589ebd2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -34,7 +34,7 @@ org.slf4j slf4j-api - 1.7.5 + 1.7.6 From a428b6cb6199dddd53c40983dfac4d770dced8ec Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 19 Mar 2014 10:09:27 +0100 Subject: [PATCH 0026/2070] fixed some small potential programming accidents --- .../asynchttpclient/date/RFC2616DateParser.java | 2 +- .../org/asynchttpclient/util/ProxyUtils.java | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/date/RFC2616DateParser.java b/api/src/main/java/org/asynchttpclient/date/RFC2616DateParser.java index bd74a18df9..effc5168a9 100644 --- a/api/src/main/java/org/asynchttpclient/date/RFC2616DateParser.java +++ b/api/src/main/java/org/asynchttpclient/date/RFC2616DateParser.java @@ -83,7 +83,7 @@ private Tokens tokenize() { } // finish lastToken - if (inToken = true) + if (inToken == true) ends[tokenCount++] = end; return new Tokens(starts, ends, tokenCount); diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index a940da8ea6..182580b1c8 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -14,14 +14,6 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.ProxyServer.Protocol; -import org.asynchttpclient.ProxyServerSelector; -import org.asynchttpclient.Request; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; @@ -30,6 +22,14 @@ import java.util.Locale; import java.util.Properties; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.ProxyServer.Protocol; +import org.asynchttpclient.ProxyServerSelector; +import org.asynchttpclient.Request; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Utilities for Proxy handling. * @@ -207,6 +207,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 fe198be5d8b3b341f32ef6d1bed2cb014d8afba8 Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 19 Mar 2014 10:28:26 +0100 Subject: [PATCH 0027/2070] added a null check for oauth1 signature calculating, now this class can be used to acquire request token within the oauth dance logic --- .../asynchttpclient/oauth/OAuthSignatureCalculator.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java index b13f5a9c58..b5d75a4faa 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java @@ -126,7 +126,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) { @@ -164,7 +166,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 ba9723b5792b520440400a71642af1918e21ea8b Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 19 Mar 2014 10:32:43 +0100 Subject: [PATCH 0028/2070] undo-ed import changes --- .../org/asynchttpclient/util/ProxyUtils.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index 182580b1c8..b48f7c7535 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -14,14 +14,6 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -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.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.ProxyServer.Protocol; @@ -30,6 +22,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +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; + /** * Utilities for Proxy handling. * From 632764093bece2d4a1075854353425530872bdd7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Mar 2014 12:00:49 +0100 Subject: [PATCH 0029/2070] No need for public modifier in an interface --- .../providers/netty/channel/ChannelPool.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java index b45dbf7cd1..39f5c7a5af 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java @@ -27,7 +27,7 @@ public interface ChannelPool { * @param connection an I/O connection * @return true if added. */ - public boolean offer(String uri, Channel connection); + boolean offer(String uri, Channel connection); /** * Remove the connection associated with the uri. @@ -35,7 +35,7 @@ public interface ChannelPool { * @param uri the uri used when invoking addConnection * @return the connection associated with the uri */ - public Channel poll(String uri); + Channel poll(String uri); /** * Remove all connections from the cache. A connection might have been associated with several uri. @@ -43,7 +43,7 @@ public interface ChannelPool { * @param connection a connection * @return the true if the connection has been removed */ - public boolean removeAll(Channel connection); + boolean removeAll(Channel connection); /** * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching @@ -51,10 +51,10 @@ public interface ChannelPool { * * @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(); } From 595a0613fcc7ad14c878ffde1dd0bf09a982990e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Mar 2014 18:48:25 +0100 Subject: [PATCH 0030/2070] When talking to a SSL proxy, AHC should use relative URIs by default, close #509 --- .../main/java/org/asynchttpclient/AsyncHttpClientConfig.java | 4 +++- api/src/main/java/org/asynchttpclient/util/MiscUtil.java | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 0140c16d23..5354b41860 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -15,6 +15,8 @@ */ package org.asynchttpclient; +import static org.asynchttpclient.util.MiscUtil.getBoolean; + import org.asynchttpclient.date.TimeConverter; import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.filter.RequestFilter; @@ -578,7 +580,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 ScheduledExecutorService reaper; private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index b65d1e4a7d..7a80e00268 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -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 db6716ad2f10f5c2d5124904725017b2ba8c3434 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Mon, 24 Mar 2014 18:24:46 -0700 Subject: [PATCH 0031/2070] Fix for #197 -- use a hostname verifier that calls out to HostnameChecker. --- .../AsyncHttpClientConfig.java | 4 +- .../util/DefaultHostnameVerifier.java | 96 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 5354b41860..c352c7f43c 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -21,7 +21,7 @@ import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.util.AllowAllHostnameVerifier; +import org.asynchttpclient.util.DefaultHostnameVerifier; import org.asynchttpclient.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; @@ -596,7 +596,7 @@ public static class Builder { private boolean allowSslConnectionPool = true; private boolean useRawUrl = false; private boolean removeQueryParamOnRedirect = true; - private HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier(); + private HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(); private int ioThreadMultiplier = 2; private boolean strict302Handling; private boolean spdyEnabled; diff --git a/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java new file mode 100644 index 0000000000..5ad7fa62b2 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java @@ -0,0 +1,96 @@ +/* + * 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 org.asynchttpclient.util; + +import sun.security.util.HostnameChecker; + +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; + +/** + * 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 HostnameVerifier extraHostnameVerifier; + + public DefaultHostnameVerifier() { + } + + public DefaultHostnameVerifier(HostnameVerifier extraHostnameVerifier) { + this.extraHostnameVerifier = extraHostnameVerifier; + } + + private boolean hostnameMatches(String hostname, SSLSession session) { + HostnameChecker checker = + HostnameChecker.getInstance(HostnameChecker.TYPE_TLS); + + boolean validCertificate = false, validPrincipal = false; + try { + Certificate[] peerCertificates = session.getPeerCertificates(); + + if (peerCertificates.length > 0 && + peerCertificates[0] instanceof X509Certificate) { + X509Certificate peerCertificate = + (X509Certificate) peerCertificates[0]; + + try { + checker.match(hostname, peerCertificate); + // Certificate matches hostname + validCertificate = true; + } catch (CertificateException ex) { + // Certificate does not match hostname + } + } else { + // Peer does not have any certificates or they aren't X.509 + } + } catch (SSLPeerUnverifiedException ex) { + // Not using certificates for peers, try verifying the principal + try { + Principal peerPrincipal = session.getPeerPrincipal(); + if (peerPrincipal instanceof KerberosPrincipal) { + validPrincipal = HostnameChecker.match(hostname, + (KerberosPrincipal) peerPrincipal); + } else { + // Can't verify principal, not Kerberos + } + } catch (SSLPeerUnverifiedException ex2) { + // Can't verify principal, no principal + } + } + + return validCertificate || validPrincipal; + } + + public boolean verify(String hostname, SSLSession session) { + if (hostnameMatches(hostname, session)) { + return true; + } else { + if (extraHostnameVerifier != null) { + return extraHostnameVerifier.verify(hostname, session); + } else { + return false; + } + } + } +} From fa056c572ab0c9b6edd05a7cc508898f35cc90d5 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Mon, 24 Mar 2014 23:25:44 -0700 Subject: [PATCH 0032/2070] Use reflection to avoid the "not part of JDK" error running tests. --- .../AsyncHttpClientConfigBean.java | 8 +- .../util/DefaultHostnameVerifier.java | 73 ++++++++++++++++--- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 3f92d0536a..f5042b37d3 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -15,6 +15,7 @@ import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.filter.ResponseFilter; +import org.asynchttpclient.util.DefaultHostnameVerifier; import org.asynchttpclient.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; @@ -70,12 +71,7 @@ void configureDefaults() { allowSslConnectionPool = true; useRawUrl = false; removeQueryParamOnRedirect = true; - hostnameVerifier = new HostnameVerifier() { - - public boolean verify(String s, SSLSession sslSession) { - return true; - } - }; + hostnameVerifier = new DefaultHostnameVerifier(); } void configureExecutors() { diff --git a/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java index 5ad7fa62b2..b5273e2920 100644 --- a/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java +++ b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java @@ -6,12 +6,12 @@ */ package org.asynchttpclient.util; -import sun.security.util.HostnameChecker; - import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.security.auth.kerberos.KerberosPrincipal; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -28,7 +28,6 @@ *

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

- */ public class DefaultHostnameVerifier implements HostnameVerifier { @@ -41,13 +40,68 @@ public DefaultHostnameVerifier(HostnameVerifier extraHostnameVerifier) { this.extraHostnameVerifier = extraHostnameVerifier; } + public final static byte TYPE_TLS = 1; + + 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); + final Object hostnameChecker = instanceMethod.invoke(null, TYPE_TLS); + return hostnameChecker; + } 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); + } + } + + private void match(Object checker, 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); + } + } + + private boolean match(Object checker, String hostname, Principal principal) { + try { + final Class hostnameCheckerClass = checker.getClass(); + final Method checkMethod = hostnameCheckerClass.getMethod("match", String.class, Principal.class); + final boolean result = (Boolean) checkMethod.invoke(null, hostname, principal); + return result; + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + private boolean hostnameMatches(String hostname, SSLSession session) { - HostnameChecker checker = - HostnameChecker.getInstance(HostnameChecker.TYPE_TLS); + boolean validCertificate = false; + boolean validPrincipal = false; - boolean validCertificate = false, validPrincipal = false; + final Object checker = getHostnameChecker(); try { - Certificate[] peerCertificates = session.getPeerCertificates(); + + final Certificate[] peerCertificates = session.getPeerCertificates(); if (peerCertificates.length > 0 && peerCertificates[0] instanceof X509Certificate) { @@ -55,7 +109,7 @@ private boolean hostnameMatches(String hostname, SSLSession session) { (X509Certificate) peerCertificates[0]; try { - checker.match(hostname, peerCertificate); + match(checker, hostname, peerCertificate); // Certificate matches hostname validCertificate = true; } catch (CertificateException ex) { @@ -69,7 +123,7 @@ private boolean hostnameMatches(String hostname, SSLSession session) { try { Principal peerPrincipal = session.getPeerPrincipal(); if (peerPrincipal instanceof KerberosPrincipal) { - validPrincipal = HostnameChecker.match(hostname, + validPrincipal = match(checker, hostname, (KerberosPrincipal) peerPrincipal); } else { // Can't verify principal, not Kerberos @@ -78,7 +132,6 @@ private boolean hostnameMatches(String hostname, SSLSession session) { // Can't verify principal, no principal } } - return validCertificate || validPrincipal; } From bbdc1b3cc6ffc0eda0dd0ad54557db557ae937f7 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Tue, 25 Mar 2014 18:21:38 -0700 Subject: [PATCH 0033/2070] Add new working certs with subjectAltName and ipaddress of 127.0.0.1 to make tests pass --- .../util/DefaultHostnameVerifier.java | 149 +++++++++--------- .../asynchttpclient/util/HostnameChecker.java | 27 ++++ .../util/ProxyHostnameChecker.java | 83 ++++++++++ api/src/test/resources/ssltest-cacerts.jks | Bin 29888 -> 31507 bytes api/src/test/resources/ssltest-keystore.jks | Bin 1445 -> 2358 bytes .../src/test/resources/ssltest-cacerts.jks | Bin 29888 -> 31507 bytes .../src/test/resources/ssltest-keystore.jks | Bin 1445 -> 2358 bytes .../src/test/resources/ssltest-cacerts.jks | Bin 29888 -> 31507 bytes .../src/test/resources/ssltest-keystore.jks | Bin 1445 -> 2358 bytes 9 files changed, 181 insertions(+), 78 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/util/HostnameChecker.java create mode 100644 api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java diff --git a/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java index b5273e2920..35f188ca93 100644 --- a/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java +++ b/api/src/main/java/org/asynchttpclient/util/DefaultHostnameVerifier.java @@ -10,12 +10,12 @@ import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.security.auth.kerberos.KerberosPrincipal; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; 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 @@ -31,119 +31,112 @@ */ 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(); } - public DefaultHostnameVerifier(HostnameVerifier extraHostnameVerifier) { - this.extraHostnameVerifier = extraHostnameVerifier; + /** + * A hostname verifier that takes an external hostname checker. Useful for testing. + * + * @param checker a hostnamechecker. + */ + public DefaultHostnameVerifier(HostnameChecker checker) { + this.checker = checker; } - public final static byte TYPE_TLS = 1; - - 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); - final Object hostnameChecker = instanceMethod.invoke(null, TYPE_TLS); - return hostnameChecker; - } 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); - } - } - - private void match(Object checker, 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); - } + /** + * 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; } - private boolean match(Object checker, String hostname, Principal principal) { - try { - final Class hostnameCheckerClass = checker.getClass(); - final Method checkMethod = hostnameCheckerClass.getMethod("match", String.class, Principal.class); - final boolean result = (Boolean) checkMethod.invoke(null, hostname, principal); - return result; - } catch (NoSuchMethodException e) { - throw new IllegalStateException(e); - } catch (InvocationTargetException e) { - throw new IllegalStateException(e); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } + /** + * 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) { - boolean validCertificate = false; - boolean validPrincipal = false; + log.log(Level.FINE, "hostname = {0}, session = {1}", new Object[] { hostname, Base64.encode(session.getId()) }); - final Object checker = getHostnameChecker(); try { - final Certificate[] peerCertificates = session.getPeerCertificates(); + if (peerCertificates.length == 0) { + log.log(Level.FINE, "No peer certificates"); + return false; + } - if (peerCertificates.length > 0 && - peerCertificates[0] instanceof X509Certificate) { - X509Certificate peerCertificate = - (X509Certificate) peerCertificates[0]; - + if (peerCertificates[0] instanceof X509Certificate) { + X509Certificate peerCertificate = (X509Certificate) peerCertificates[0]; + log.log(Level.FINE, "peerCertificate = {0}", peerCertificate); try { - match(checker, hostname, peerCertificate); - // Certificate matches hostname - validCertificate = true; + checker.match(hostname, peerCertificate); + // Certificate matches hostname if no exception is thrown. + return true; } catch (CertificateException ex) { - // Certificate does not match hostname + log.log(Level.FINE, "Certificate does not match hostname", ex); } } else { - // Peer does not have any certificates or they aren't X.509 + log.log(Level.FINE, "Peer does not have any certificates or they aren't X.509"); } + return false; } catch (SSLPeerUnverifiedException ex) { - // Not using certificates for peers, try verifying the principal + 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) { - validPrincipal = match(checker, hostname, - (KerberosPrincipal) peerPrincipal); + return checker.match(hostname, (KerberosPrincipal) peerPrincipal); } else { - // Can't verify principal, not Kerberos + 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; } - return validCertificate || validPrincipal; } + /** + * 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 { - if (extraHostnameVerifier != null) { - return extraHostnameVerifier.verify(hostname, session); - } else { - return false; - } + return extraHostnameVerifier != null && extraHostnameVerifier.verify(hostname, session); } } } diff --git a/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java b/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java new file mode 100644 index 0000000000..daf012deca --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.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/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java b/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java new file mode 100644 index 0000000000..1355d9084f --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.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/api/src/test/resources/ssltest-cacerts.jks b/api/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 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 O?b_CY5k7ykl~;#8!Ou+q delta 490 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 O?b_CY5k7ykl~;#8!Ou+q delta 490 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 KW;nz!2r Date: Wed, 26 Mar 2014 14:06:06 +0100 Subject: [PATCH 0034/2070] 511: GrizzlyAsyncHttpProvider not honoring usePreemtiveAuth --- .../asynchttpclient/async/BasicAuthTest.java | 20 +++++++++-- .../filters/AsyncHttpClientFilter.java | 36 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 144556d9da..2f5b89073b 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -34,6 +34,7 @@ import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Realm; +import org.asynchttpclient.Realm.AuthScheme; import org.asynchttpclient.Response; import org.asynchttpclient.SimpleAsyncHttpClient; import org.asynchttpclient.consumers.AppendableBodyConsumer; @@ -64,6 +65,8 @@ public abstract class BasicAuthTest extends AbstractBasicTest { protected static final String MY_MESSAGE = "my message"; private Server server2; + private Server serverNoAuth; + private int portNoAuth; public abstract String getProviderClass(); @@ -72,6 +75,7 @@ public abstract class BasicAuthTest extends AbstractBasicTest { public void setUpGlobal() throws Exception { port1 = findFreePort(); port2 = findFreePort(); + portNoAuth = findFreePort(); server = newJettyHttpServer(port1); addBasicAuthHandler(server, false, configureHandler()); @@ -81,6 +85,11 @@ public void setUpGlobal() throws Exception { addDigestAuthHandler(server2, true, new RedirectHandler()); server2.start(); + // need noAuth server to verify the preemptive auth mode (see basicAuthTetPreemtiveTest) + serverNoAuth = newJettyHttpServer(portNoAuth); + serverNoAuth.setHandler(new SimpleHandler()); + serverNoAuth.start(); + logger.info("Local HTTP server started successfully"); } @@ -88,6 +97,7 @@ public void setUpGlobal() throws Exception { public void tearDownGlobal() throws Exception { super.tearDownGlobal(); server2.stop(); + serverNoAuth.stop(); } @Override @@ -100,6 +110,10 @@ protected String getTargetUrl2() { return "http://127.0.0.1/" + port2 + "/uff"; } + protected String getTargetUrlNoAuth() { + return "http://127.0.0.1/" + portNoAuth + "/"; + } + @Override public AbstractHandler configureHandler() throws Exception { return new SimpleHandler(); @@ -247,8 +261,10 @@ public Integer onCompleted() throws Exception { public void basicAuthTestPreemtiveTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); try { - Future f = client.prepareGet(getTargetUrl())// - .setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).setUsePreemptiveAuth(true).build())// + // send the request to the no-auth endpoint to be able to verify the auth header is + // really sent preemptively for the initial call. + Future f = client.prepareGet(getTargetUrlNoAuth())// + .setRealm((new Realm.RealmBuilder()).setScheme(AuthScheme.BASIC).setPrincipal(USER).setPassword(ADMIN).setUsePreemptiveAuth(true).build())// .execute(); Response resp = f.get(3, TimeUnit.SECONDS); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 47b6007e25..490e38776d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -14,15 +14,20 @@ package org.asynchttpclient.providers.grizzly.filters; import static org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter.getHandshakeError; +import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.NTLM_ENGINE; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; +import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; +import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.FluentStringsMap; import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Realm; import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.Response; @@ -262,6 +267,7 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, addHostHeader(request, uri, requestPacket); addGeneralHeaders(request, requestPacket); addCookies(request, requestPacket); + addAuthorizationHeader(request, requestPacket); initTransferCompletionHandler(request, httpTxContext.getHandler()); @@ -398,6 +404,36 @@ private static void addHostHeader(final Request request, final URI uri, final Ht } } + 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 computeBasicAuthentication(realm); + case DIGEST: + return computeDigestAuthentication(realm); + case NTLM: + return NTLM_ENGINE.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); + default: + return null; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + private static boolean isUpgradeRequest(final AsyncHandler handler) { return (handler instanceof UpgradeHandler); } From f776258f820df5b7a9faca5b4fef6f4b1e85818e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 26 Mar 2014 18:24:08 +0100 Subject: [PATCH 0035/2070] Expose RequestBuilder reset methods, close #515 --- .../org/asynchttpclient/RequestBuilderBase.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 810e102483..fb173e47ed 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -466,18 +466,26 @@ 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; request.length = -1; } - private void resetMultipartData() { + public void resetMultipartData() { request.parts = null; } From c9b5391e94cb5c81476d8d154d8b02d06f7804ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Mar 2014 04:03:38 +0100 Subject: [PATCH 0036/2070] Advertise 1.8.4 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebd1fb6b13..aa1cacd146 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.3 + 1.8.4 ``` From d6a16a5175d14f12a0dd57da08333ed4ab6bdf04 Mon Sep 17 00:00:00 2001 From: Tong Wu Date: Tue, 1 Apr 2014 10:06:11 -0700 Subject: [PATCH 0037/2070] use passed in config instead of default config. This is to fix config inconsistency between newly created client's config and client's provider's config --- .../main/java/org/asynchttpclient/DefaultAsyncHttpClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java index 4cb934af6b..e6ba817ea2 100644 --- a/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java @@ -105,7 +105,7 @@ public DefaultAsyncHttpClient(AsyncHttpClientConfig config) { * @param providerClass a {@link AsyncHttpProvider} */ public DefaultAsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { - this(loadProvider(providerClass, config), new AsyncHttpClientConfig.Builder().build()); + this(loadProvider(providerClass, config), config); } /** From f49fcf8a25eee127b1458137b5207ae6985fa4ab Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 11:56:12 +0200 Subject: [PATCH 0038/2070] Make disposition-type configurable, close #522 --- .../org/asynchttpclient/multipart/Part.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index 849d721c1f..9b6535e22f 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -41,7 +41,17 @@ public abstract class Part { /** * Content dispostion as a byte array */ - public static final byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: form-data; name=".getBytes(StandardCharsets.US_ASCII); + public static final byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: ".getBytes(StandardCharsets.US_ASCII); + + /** + * form-data as a byte array + */ + public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = "form-data".getBytes(StandardCharsets.US_ASCII); + + /** + * name as a byte array + */ + public static final byte[] NAME_BYTES = "; name=".getBytes(StandardCharsets.US_ASCII); /** * Content type header as a byte array @@ -108,6 +118,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; + } + protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException { visitor.withBytes(EXTRA_BYTES); visitor.withBytes(boundary); @@ -117,6 +141,8 @@ protected void visitDispositionHeader(PartVisitor visitor) throws IOException { if (getName() != null) { visitor.withBytes(CRLF_BYTES); visitor.withBytes(CONTENT_DISPOSITION_BYTES); + visitor.withBytes(dispositionType != null? dispositionType.getBytes(StandardCharsets.US_ASCII): FORM_DATA_DISPOSITION_TYPE_BYTES); + visitor.withBytes(NAME_BYTES); visitor.withBytes(QUOTE_BYTES); visitor.withBytes(getName().getBytes(StandardCharsets.US_ASCII)); visitor.withBytes(QUOTE_BYTES); From 4ecc87fd3ab325dbf497af08846a5b833089a763 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 12:33:35 +0200 Subject: [PATCH 0039/2070] Fix license headers --- .../multipart/AbstractFilePart.java | 19 ++++++++----------- .../multipart/ByteArrayPart.java | 19 ++++++++----------- .../multipart/CounterPartVisitor.java | 19 ++++++++----------- .../asynchttpclient/multipart/FilePart.java | 19 ++++++++----------- .../org/asynchttpclient/multipart/Part.java | 19 ++++++++----------- .../asynchttpclient/multipart/PartBase.java | 19 ++++++++----------- .../multipart/PartVisitor.java | 19 ++++++++----------- .../asynchttpclient/multipart/StringPart.java | 19 ++++++++----------- 8 files changed, 64 insertions(+), 88 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index 14edabbd52..ea5efc5783 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index 0dc115be98..1959d9c005 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java index 738db27144..e751cdbfd0 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index b05802807d..739bd8d6c9 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index 9b6535e22f..d4f7b3f801 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 2f446d18c5..208a5259c6 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java index 150cdfa734..b9a6c6df54 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index 1dad2f0be3..b8061a3088 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -1,17 +1,14 @@ /* - * 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 org.asynchttpclient.multipart; From 4bd48241348ddea1084cf9d064ec3f68768f1487 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 14:10:40 +0200 Subject: [PATCH 0040/2070] Minor clean up --- .../org/asynchttpclient/multipart/Part.java | 27 ++++------ .../asynchttpclient/multipart/PartBase.java | 50 ++++++++++--------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index d4f7b3f801..fc117d6981 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -44,7 +44,7 @@ public abstract class Part { * form-data as a byte array */ public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = "form-data".getBytes(StandardCharsets.US_ASCII); - + /** * name as a byte array */ @@ -105,6 +105,13 @@ public abstract class Part { */ public abstract String getContentId(); + /** + * Gets the disposition-type to be used in Content-Disposition header + * + * @return the disposition-type + */ + public abstract String getDispositionType(); + /** * Tests if this part can be sent more than once. * @@ -115,30 +122,18 @@ 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; - } - protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException { visitor.withBytes(EXTRA_BYTES); visitor.withBytes(boundary); } protected void visitDispositionHeader(PartVisitor visitor) throws IOException { + if (getName() != null) { visitor.withBytes(CRLF_BYTES); visitor.withBytes(CONTENT_DISPOSITION_BYTES); - visitor.withBytes(dispositionType != null? dispositionType.getBytes(StandardCharsets.US_ASCII): FORM_DATA_DISPOSITION_TYPE_BYTES); + visitor.withBytes(getDispositionType() != null ? getDispositionType().getBytes(StandardCharsets.US_ASCII) + : FORM_DATA_DISPOSITION_TYPE_BYTES); visitor.withBytes(NAME_BYTES); visitor.withBytes(QUOTE_BYTES); visitor.withBytes(getName().getBytes(StandardCharsets.US_ASCII)); diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 208a5259c6..b696f657a4 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -15,27 +15,35 @@ public abstract class PartBase extends Part { /** - * Name of the file part. + * The name of the form field, part of the Content-Disposition header */ private final String name; /** - * Content type of the file part. + * The main part of the Content-Type header */ private final String contentType; /** - * Content encoding of the file part. + * The charset (part of Content-Type header) */ private final String charSet; /** - * The transfer encoding. + * 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. * @@ -57,43 +65,37 @@ public PartBase(String name, String contentType, String charSet, String transfer this.contentId = contentId; } - /** - * Returns the name. - * - * @return The name. - */ + @Override public String getName() { return this.name; } - /** - * Returns the content type of this part. - * - * @return String The name. - */ + @Override public String getContentType() { return this.contentType; } - /** - * Return the character encoding of this part. - * - * @return String The name. - */ + @Override public String getCharSet() { return this.charSet; } - /** - * Returns the transfer encoding of this part. - * - * @return String The name. - */ + @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; + } } From 3dcb179047c70c223f2ecf4ad3a54b8f7f465bc0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 14:17:33 +0200 Subject: [PATCH 0041/2070] Multipart name should be optional, close #523 --- .../org/asynchttpclient/multipart/Part.java | 24 +++++++++---------- .../asynchttpclient/multipart/PartBase.java | 6 +---- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index fc117d6981..2f103457c7 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -128,12 +128,11 @@ protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOExcepti } protected void visitDispositionHeader(PartVisitor visitor) throws IOException { - + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CONTENT_DISPOSITION_BYTES); + visitor.withBytes(getDispositionType() != null ? getDispositionType().getBytes(StandardCharsets.US_ASCII) + : FORM_DATA_DISPOSITION_TYPE_BYTES); if (getName() != null) { - visitor.withBytes(CRLF_BYTES); - visitor.withBytes(CONTENT_DISPOSITION_BYTES); - visitor.withBytes(getDispositionType() != null ? getDispositionType().getBytes(StandardCharsets.US_ASCII) - : FORM_DATA_DISPOSITION_TYPE_BYTES); visitor.withBytes(NAME_BYTES); visitor.withBytes(QUOTE_BYTES); visitor.withBytes(getName().getBytes(StandardCharsets.US_ASCII)); @@ -239,14 +238,15 @@ public long length(byte[] boundary) { } } - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - * @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(); } public abstract long write(WritableByteChannel target, byte[] boundary) throws IOException; diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index b696f657a4..307bd68841 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -47,17 +47,13 @@ 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 * @param contentId The content id, or null */ public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) { - - if (name == null) { - throw new NullPointerException("name"); - } this.name = name; this.contentType = contentType; this.charSet = charSet; From 050e5344e3c77568d6b9a7c7107db9eb64c2396d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 14:41:36 +0200 Subject: [PATCH 0042/2070] Minor clean up, turn Part into an interface --- .../multipart/AbstractFilePart.java | 52 ++++-- .../multipart/ByteArrayPart.java | 8 +- .../multipart/CounterPartVisitor.java | 5 + .../asynchttpclient/multipart/FilePart.java | 8 +- .../multipart/OutputStreamPartVisitor.java | 5 + .../org/asynchttpclient/multipart/Part.java | 164 +++--------------- .../asynchttpclient/multipart/PartBase.java | 134 +++++++++++++- .../multipart/PartVisitor.java | 3 +- 8 files changed, 204 insertions(+), 175 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index ea5efc5783..d366d3da09 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -12,7 +12,8 @@ */ package org.asynchttpclient.multipart; -import org.asynchttpclient.util.StandardCharsets; +import static org.asynchttpclient.util.StandardCharsets.US_ASCII; +import static org.asynchttpclient.util.StandardCharsets.ISO_8859_1; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -32,7 +33,7 @@ public abstract class AbstractFilePart extends PartBase { /** * Default charset of file attachments. */ - public static final String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name(); + public static final String DEFAULT_CHARSET = ISO_8859_1.name(); /** * Default transfer encoding of file attachments. @@ -42,10 +43,12 @@ public abstract class AbstractFilePart extends PartBase { /** * Attachment's file name as a byte array */ - private static final byte[] FILE_NAME_BYTES = "; filename=".getBytes(StandardCharsets.US_ASCII); + private static final byte[] FILE_NAME_BYTES = "; filename=".getBytes(US_ASCII); private long stalledTime = -1L; + private String fileName; + /** * FilePart Constructor. * @@ -64,27 +67,16 @@ public AbstractFilePart(String name, String contentType, String charset, String DEFAULT_TRANSFER_ENCODING, contentId); } - public abstract String getFileName(); - protected void visitDispositionHeader(PartVisitor visitor) throws IOException { super.visitDispositionHeader(visitor); - String filename = getFileName(); - if (filename != null) { + if (fileName != null) { visitor.withBytes(FILE_NAME_BYTES); - visitor.withBytes(QUOTE_BYTES); - visitor.withBytes(filename.getBytes(StandardCharsets.US_ASCII)); - visitor.withBytes(QUOTE_BYTES); + visitor.withByte(QUOTE_BYTE); + visitor.withBytes(fileName.getBytes(US_ASCII)); + visitor.withByte(QUOTE_BYTE); } } - public void setStalledTime(long ms) { - stalledTime = ms; - } - - public long getStalledTime() { - return stalledTime; - } - protected byte[] generateFileStart(byte[] boundary) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); @@ -104,4 +96,28 @@ protected byte[] generateFileEnd() throws IOException { 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/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index 1959d9c005..a7cd65337e 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java @@ -19,7 +19,6 @@ public class ByteArrayPart extends AbstractFilePart { private final byte[] bytes; - private final String fileName; public ByteArrayPart(String name, byte[] bytes) { this(name, bytes, null); @@ -43,12 +42,7 @@ public ByteArrayPart(String name, byte[] bytes, String contentType, String chars throw new NullPointerException("bytes"); } this.bytes = bytes; - this.fileName = fileName; - } - - @Override - public String getFileName() { - return fileName; + setFileName(fileName); } @Override diff --git a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java index e751cdbfd0..dc7b822163 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java @@ -23,6 +23,11 @@ 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/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index 739bd8d6c9..ed4cb93f09 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -29,7 +29,6 @@ public class FilePart extends AbstractFilePart { private static final Logger LOGGER = LoggerFactory.getLogger(FilePart.class); private final File file; - private final String fileName; public FilePart(String name, File file) { this(name, file, null, null); @@ -59,12 +58,7 @@ public FilePart(String name, File file, String contentType, String charset, Stri if (!file.canRead()) { throw new IllegalArgumentException("File is not readable " + file.getAbsolutePath()); } - this.fileName = fileName != null ? fileName : file.getName(); - } - - @Override - public String getFileName() { - return fileName; + setFileName(fileName != null ? fileName : file.getName()); } @Override diff --git a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java index 7f57532459..518962f8d9 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java @@ -31,6 +31,11 @@ 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/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index 2f103457c7..66758c7df8 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/multipart/Part.java @@ -12,178 +12,105 @@ */ package org.asynchttpclient.multipart; -import org.asynchttpclient.util.StandardCharsets; +import static org.asynchttpclient.util.StandardCharsets.US_ASCII; import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; -public abstract class Part { +public interface Part { /** * Carriage return/linefeed as a byte array */ - public static final byte[] CRLF_BYTES = "\r\n".getBytes(StandardCharsets.US_ASCII); + byte[] CRLF_BYTES = "\r\n".getBytes(US_ASCII); /** - * Content dispostion as a byte array + * Content dispostion as a byte */ - public static final byte[] QUOTE_BYTES = "\"".getBytes(StandardCharsets.US_ASCII); + byte QUOTE_BYTE = '\"'; /** * Extra characters as a byte array */ - public static final byte[] EXTRA_BYTES = "--".getBytes(StandardCharsets.US_ASCII); + byte[] EXTRA_BYTES = "--".getBytes(US_ASCII); /** * Content dispostion as a byte array */ - public static final byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: ".getBytes(StandardCharsets.US_ASCII); + byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: ".getBytes(US_ASCII); /** * form-data as a byte array */ - public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = "form-data".getBytes(StandardCharsets.US_ASCII); + byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = "form-data".getBytes(US_ASCII); /** * name as a byte array */ - public static final byte[] NAME_BYTES = "; name=".getBytes(StandardCharsets.US_ASCII); + byte[] NAME_BYTES = "; name=".getBytes(US_ASCII); /** * Content type header as a byte array */ - public static final byte[] CONTENT_TYPE_BYTES = "Content-Type: ".getBytes(StandardCharsets.US_ASCII); + byte[] CONTENT_TYPE_BYTES = "Content-Type: ".getBytes(US_ASCII); /** * Content charset as a byte array */ - public static final byte[] CHARSET_BYTES = "; charset=".getBytes(StandardCharsets.US_ASCII); + byte[] CHARSET_BYTES = "; charset=".getBytes(US_ASCII); /** * Content type header as a byte array */ - public static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = "Content-Transfer-Encoding: ".getBytes(StandardCharsets.US_ASCII); + byte[] CONTENT_TRANSFER_ENCODING_BYTES = "Content-Transfer-Encoding: ".getBytes(US_ASCII); /** * Content type header as a byte array */ - public static final byte[] CONTENT_ID_BYTES = "Content-ID: ".getBytes(StandardCharsets.US_ASCII); + byte[] CONTENT_ID_BYTES = "Content-ID: ".getBytes(US_ASCII); /** * Return the name of this part. * * @return The name. */ - public abstract String getName(); + 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(); + 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(); + 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(); + 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(); + String getContentId(); /** * Gets the disposition-type to be used in Content-Disposition header * * @return the disposition-type */ - public abstract String getDispositionType(); - - /** - * 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; - } - - 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(StandardCharsets.US_ASCII) - : FORM_DATA_DISPOSITION_TYPE_BYTES); - if (getName() != null) { - visitor.withBytes(NAME_BYTES); - visitor.withBytes(QUOTE_BYTES); - visitor.withBytes(getName().getBytes(StandardCharsets.US_ASCII)); - visitor.withBytes(QUOTE_BYTES); - } - } - - 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(StandardCharsets.US_ASCII)); - String charSet = getCharSet(); - if (charSet != null) { - visitor.withBytes(CHARSET_BYTES); - visitor.withBytes(charSet.getBytes(StandardCharsets.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(StandardCharsets.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(StandardCharsets.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; + String getDispositionType(); /** * Write all the data to the output stream. If you override this method make sure to override #length() as well @@ -195,59 +122,14 @@ protected void visitEnd(PartVisitor visitor) throws IOException { * @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); - } + 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. */ - 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("name=").append(getName())// - .append(" contentType=").append(getContentType())// - .append(" charset=").append(getCharSet())// - .append(" tranferEncoding=").append(getTransferEncoding())// - .append(" contentId=").append(getContentId())// - .append(" dispositionType=").append(getDispositionType())// - .toString(); - } - - public abstract long write(WritableByteChannel target, byte[] boundary) throws IOException; + long length(byte[] boundary); + + long write(WritableByteChannel target, byte[] boundary) throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 307bd68841..2d9d274705 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -12,7 +12,12 @@ */ package org.asynchttpclient.multipart; -public abstract class PartBase extends Part { +import static org.asynchttpclient.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 @@ -61,6 +66,133 @@ public PartBase(String name, String contentType, String charSet, String transfer 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; diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java index b9a6c6df54..a7b8b84492 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java @@ -16,5 +16,6 @@ public interface PartVisitor { - public void withBytes(byte[] bytes) throws IOException; + void withBytes(byte[] bytes) throws IOException; + void withByte(byte b) throws IOException; } From b6ad32940f56bcaff75cb2c7b5c24d96a7a9f38b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 15:11:07 +0200 Subject: [PATCH 0043/2070] Make multipart FilePart charset optional, close #524 --- .../asynchttpclient/multipart/AbstractFilePart.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index d366d3da09..a4d5f4e9b9 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java @@ -13,7 +13,6 @@ package org.asynchttpclient.multipart; import static org.asynchttpclient.util.StandardCharsets.US_ASCII; -import static org.asynchttpclient.util.StandardCharsets.ISO_8859_1; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -30,11 +29,6 @@ public abstract class AbstractFilePart 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.name(); - /** * Default transfer encoding of file attachments. */ @@ -59,11 +53,10 @@ public abstract class AbstractFilePart extends PartBase { * @param contentType * the content type for this part, if null the {@link #DEFAULT_CONTENT_TYPE default} is used * @param charset - * the charset encoding for this part, if null the {@link #DEFAULT_CHARSET default} is used - * @param contentId + * 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 == null ? DEFAULT_CHARSET : charset, + super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, DEFAULT_TRANSFER_ENCODING, contentId); } From 80f9bed2fcf27dc49e2f5912f6627e389776c094 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 15:29:49 +0200 Subject: [PATCH 0044/2070] Percent encoding user info fix, port #521 on master --- .../main/java/org/asynchttpclient/RequestBuilderBase.java | 2 +- .../java/org/asynchttpclient/async/RequestBuilderTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index fb173e47ed..cd4cd2df1d 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -170,7 +170,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/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java index 7d1408c1d0..d4d3d8cd0b 100644 --- a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/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 a94bd62f170aebb9a041bc150bf3944de89858b4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Apr 2014 10:51:32 +0200 Subject: [PATCH 0045/2070] Advertise 1.8.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa1cacd146..9fc2579a1f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.4 + 1.8.5 ``` From 8e4d787565b9bc3929c9e24c82accd6c8b7233e7 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Sun, 6 Apr 2014 17:52:28 -0700 Subject: [PATCH 0046/2070] Move the hostname verification to after the SSL handshake has completed. --- .../asynchttpclient/async/BasicHttpsTest.java | 9 +- .../asynchttpclient/async/util/TestUtils.java | 96 ++++++++++++------- .../providers/grizzly/ConnectionManager.java | 52 +++++----- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../netty/request/NettyConnectListener.java | 40 ++++++-- 5 files changed, 130 insertions(+), 69 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java index 7bc7233783..24675057e7 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java @@ -30,6 +30,7 @@ import javax.net.ssl.SSLHandshakeException; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.net.ConnectException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -100,17 +101,19 @@ public void reconnectsAfterFailedCertificationPath() throws Exception { 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); } catch (final ExecutionException e) { - Throwable cause = e.getCause(); + cause = e.getCause(); if (cause instanceof ConnectException) { - assertNotNull(cause.getCause()); + //assertNotNull(cause.getCause()); assertTrue(cause.getCause() instanceof SSLHandshakeException, "Expected an SSLHandshakeException, got a " + cause.getCause()); } else { - assertTrue(cause instanceof SSLHandshakeException, "Expected an SSLHandshakeException, got a " + cause); + assertTrue(cause instanceof IOException, "Expected an IOException, got a " + cause); } } + assertNotNull(cause); trusted.set(true); diff --git a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java index 75aab93fe0..7c9b46c50b 100644 --- a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java +++ b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java @@ -22,11 +22,7 @@ import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.ssl.SslContextFactory; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +import javax.net.ssl.*; import java.io.File; import java.io.FileNotFoundException; @@ -38,8 +34,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.Charset; -import java.security.KeyStore; -import java.security.SecureRandom; +import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -149,7 +144,6 @@ public static void addHttpsConnector(Server server, int port) throws URISyntaxEx ServerConnector connector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(httpsConfig)); connector.setPort(port); - server.addConnector(connector); server.addConnector(connector); } @@ -191,21 +185,38 @@ private static void addAuthHandler(Server server, String auth, LoginAuthenticato server.setHandler(security); } + 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 = HostnameVerifierTest.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[] { dummyTrustManager(trust) }; + KeyManager[] keyManagers = createKeyManagers(); + TrustManager[] trustManagers = new TrustManager[] { dummyTrustManager(trust, (X509TrustManager) createTrustManagers()[0]) }; SecureRandom secureRandom = new SecureRandom(); SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -217,21 +228,40 @@ public static SSLContext createSSLContext(AtomicBoolean trust) { } } - private static final TrustManager dummyTrustManager(final AtomicBoolean trust) { - return new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } + public static class DummyTrustManager implements X509TrustManager { - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - } + private final X509TrustManager tm; + private final AtomicBoolean trust; - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - if (!trust.get()) { - throw new CertificateException("Server certificate not trusted."); - } + public DummyTrustManager(final AtomicBoolean trust, final X509TrustManager tm) { + this.trust = trust; + this.tm = tm; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + tm.checkClientTrusted(chain, authType); + } + + @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); + } public static File getClasspathFile(String file) throws FileNotFoundException { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index 41984d449f..e90f418664 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -20,18 +20,22 @@ import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; +import org.asynchttpclient.util.Base64; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; -import org.glassfish.grizzly.EmptyCompletionHandler; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.GrizzlyFuture; import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.connectionpool.EndpointKey; import org.glassfish.grizzly.filterchain.FilterChainBuilder; 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 org.glassfish.grizzly.utils.IdleTimeoutFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; @@ -51,6 +55,8 @@ public class ConnectionManager { + private final static Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class); + private static final Attribute DO_NOT_CACHE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(ConnectionManager.class .getName()); private final ConnectionPool connectionPool; @@ -60,13 +66,15 @@ public class ConnectionManager { private final FilterChainBuilder secureBuilder; private final FilterChainBuilder nonSecureBuilder; private final boolean asyncConnect; + private final SSLFilter sslFilter; // ------------------------------------------------------------ Constructors ConnectionManager(final GrizzlyAsyncHttpProvider provider,// final ConnectionPool connectionPool,// final FilterChainBuilder secureBuilder,// - final FilterChainBuilder nonSecureBuilder) { + final FilterChainBuilder nonSecureBuilder,// + final SSLFilter sslFilter) { this.provider = provider; final AsyncHttpClientConfig config = provider.getClientConfig(); @@ -87,6 +95,7 @@ public class ConnectionManager { AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); asyncConnect = providerConfig instanceof GrizzlyAsyncHttpProviderConfig ? GrizzlyAsyncHttpProviderConfig.class.cast(providerConfig) .isAsyncConnectMode() : false; + this.sslFilter = sslFilter; } // ---------------------------------------------------------- Public Methods @@ -95,7 +104,7 @@ public void doTrackedConnection(final Request request,// final GrizzlyResponseFuture requestFuture,// final CompletionHandler connectHandler) throws IOException { final EndpointKey key = getEndPointKey(request, requestFuture.getProxyServer()); - CompletionHandler handler = wrapHandler(request, getVerifier(), connectHandler); + CompletionHandler handler = wrapHandler(request, getVerifier(), connectHandler, sslFilter); if (asyncConnect) { connectionPool.take(key, handler); } else { @@ -136,37 +145,32 @@ public Connection obtainConnection(final Request request, final GrizzlyResponseF // --------------------------------------------------Package Private Methods static CompletionHandler wrapHandler(final Request request, final HostnameVerifier verifier, - final CompletionHandler delegate) { + final CompletionHandler delegate, final SSLFilter sslFilter) { final URI uri = request.getURI(); if (Utils.isSecure(uri) && verifier != null) { - return new EmptyCompletionHandler() { + SSLBaseFilter.HandshakeListener handshakeListener = new SSLBaseFilter.HandshakeListener() { @Override - public void completed(Connection result) { - final String host = uri.getHost(); - final SSLSession session = SSLUtils.getSSLEngine(result).getSession(); - if (!verifier.verify(host, session)) { - failed(new ConnectException("Host name verification failed for host " + host)); - } else { - delegate.completed(result); - } - + public void onStart(Connection connection) { + // do nothing + LOGGER.debug("SSL Handshake onStart: "); } @Override - public void cancelled() { - delegate.cancelled(); - } + public void onComplete(Connection connection) { + sslFilter.removeHandshakeListener(this); - @Override - public void failed(Throwable throwable) { - delegate.failed(throwable); - } + final String host = uri.getHost(); + final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); + LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); - @Override - public void updated(Connection result) { - delegate.updated(result); + 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); + } } }; + sslFilter.addHandshakeListener(handshakeListener); } return delegate; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index a7d221093f..722a1b7e88 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -334,7 +334,7 @@ public void onTimeout(Connection connection) { } else { pool = null; } - connectionManager = new ConnectionManager(this, pool, secure, nonSecure); + connectionManager = new ConnectionManager(this, pool, secure, nonSecure, filter); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 7bfc6d8717..c023406e44 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -16,10 +16,13 @@ */ package org.asynchttpclient.providers.netty.request; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.future.StackTraceInspector; +import org.asynchttpclient.util.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +31,10 @@ import io.netty.channel.ChannelFutureListener; import io.netty.handler.ssl.SslHandler; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLSession; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; @@ -54,15 +61,32 @@ public NettyResponseFuture future() { public void onFutureSuccess(final Channel channel) throws ConnectException { Channels.setDefaultAttribute(channel, future); - SslHandler sslHandler = Channels.getSslHandler(channel); - - if (sslHandler != null && !config.getHostnameVerifier().verify(future.getURI().getHost(), sslHandler.engine().getSession())) { - ConnectException exception = new ConnectException("HostnameVerifier exception"); - future.abort(exception); - throw exception; + final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); + final SslHandler sslHandler = Channels.getSslHandler(channel); + if (hostnameVerifier != null && sslHandler != null) { + final String host = future.getURI().getHost(); + sslHandler.handshakeFuture().addListener(new GenericFutureListener>() { + @Override + public void operationComplete(Future handshakeFuture) throws Exception { + if (handshakeFuture.isSuccess()) { + Channel channel = (Channel) handshakeFuture.getNow(); + SSLEngine engine = sslHandler.engine(); + 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 { + requestSender.writeRequest(future, channel); + } + } + } + }); + } else { + requestSender.writeRequest(future, channel); } - - requestSender.writeRequest(future, channel); } public void onFutureFailure(Channel channel, Throwable cause) { From 33caaf4356ad2f38b990e9763f09acfa51bcf1d5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Apr 2014 11:15:44 +0200 Subject: [PATCH 0047/2070] Use Netty Timer interface instead of HashedWheelTimer, close #528 --- .../netty/NettyAsyncHttpProviderConfig.java | 12 +++++----- .../providers/netty/channel/Channels.java | 24 ++++++++++++------- .../netty/channel/DefaultChannelPool.java | 14 +++++------ 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index c012e6b27a..f4a0022bad 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -28,7 +28,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; -import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; import java.util.HashMap; import java.util.Map; @@ -89,7 +89,7 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig future, Throwable t) { } public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { - return hashedWheelTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); + return nettyTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); } public static SslHandler getSslHandler(Channel channel) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index cfae7c3883..3d9fa7fb7f 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -21,8 +21,8 @@ import org.slf4j.LoggerFactory; import io.netty.channel.Channel; -import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; +import io.netty.util.Timer; import io.netty.util.TimerTask; import java.util.ArrayList; @@ -43,20 +43,20 @@ public class DefaultChannelPool implements ChannelPool { private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); private final AtomicBoolean closed = 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 DefaultChannelPool(AsyncHttpClientConfig config, HashedWheelTimer hashedWheelTimer) { + public DefaultChannelPool(AsyncHttpClientConfig config, Timer nettyTimer) { this(config.getMaxTotalConnections(),// config.getMaxConnectionPerHost(),// config.getIdleConnectionInPoolTimeoutInMs(),// config.isSslConnectionPoolEnabled(),// config.getMaxConnectionLifeTimeInMs(),// - hashedWheelTimer); + nettyTimer); } public DefaultChannelPool(// @@ -65,18 +65,18 @@ public DefaultChannelPool(// long maxIdleTime,// boolean sslConnectionPoolEnabled,// int maxConnectionLifeTimeInMs,// - 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); + nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); } private static class IdleChannel { From a4d487df6565473a09cf580f4dd134d258906234 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Apr 2014 19:24:09 +0200 Subject: [PATCH 0048/2070] Port #530 on master, close #529 --- api/src/main/java/org/asynchttpclient/Realm.java | 5 ++++- .../providers/netty/handler/HttpProtocol.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 8676bdc2eb..cf2e07a3f6 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -400,7 +400,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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 61bbe02c0a..032a3d9ae1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -227,7 +227,7 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req .parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); } - Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(URI.create(request.getUrl()).getPath()).build(); + Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(request.getURI().getPath()).build(); final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); LOGGER.debug("Sending authentication to {}", request.getUrl()); From 285c2f8a7ef12d09c10e0881aa1339b6bc79ede0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Apr 2014 00:53:06 +0200 Subject: [PATCH 0049/2070] Update README to mention 1.8.6, close #531 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fc2579a1f..cfb1fcca24 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.5 + 1.8.6 ``` From 3b41defac647ead03343da8b81c7fae9da8b5cb1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Apr 2014 22:54:03 +0200 Subject: [PATCH 0050/2070] MakeTimeoutsHolder threadsafe, close #534 --- .../providers/netty/request/timeout/TimeoutsHolder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java index e9de57017c..309d4712a1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java @@ -17,18 +17,19 @@ import io.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 f96bcbbe906c1e472fbbd7cca5cfaf3778db02d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Apr 2014 23:03:42 +0200 Subject: [PATCH 0051/2070] Release 1.8.7 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cfb1fcca24..ab674947c3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.6 + 1.8.7 ``` From 56b7228f52e34300ce209c25fdc55775dff90e16 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Apr 2014 14:59:30 +0200 Subject: [PATCH 0052/2070] Add remote channel ip address to read timeout exception, port #538 on master --- .../providers/netty/future/NettyResponseFuture.java | 5 +++++ .../netty/request/timeout/RequestTimeoutTimerTask.java | 5 +++-- .../providers/netty/NettyPerRequestTimeoutTest.java | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 01739dc8a2..06f1d538e4 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -34,6 +34,7 @@ import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; +import java.net.SocketAddress; import java.net.URI; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; @@ -468,6 +469,10 @@ public boolean canRetry() { return true; } + public SocketAddress getChannelRemoteAddress() { + return channel() != null? channel().remoteAddress(): null; + } + public void setRequest(Request request) { this.request = request; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 65dcdb0387..98c5198895 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -45,8 +45,9 @@ 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/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java index 706baa3730..960a039d9a 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyPerRequestTimeoutTest.java @@ -22,7 +22,9 @@ public class NettyPerRequestTimeoutTest extends PerRequestTimeoutTest { @Override 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 63c51410d8a73e9406f996a06d4431ac70c14a9e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Apr 2014 10:32:33 +0200 Subject: [PATCH 0053/2070] idleConnectionTimeout might have been dropped or not set, close #534 --- .../netty/request/timeout/TimeoutsHolder.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java index 309d4712a1..a27e903510 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/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 0f1a04f56e0bf94af22145d017cceab675f9a439 Mon Sep 17 00:00:00 2001 From: Yubao Liu Date: Mon, 21 Apr 2014 18:40:54 +0800 Subject: [PATCH 0054/2070] set correct default maxConnectionLifetimeInMs com.ning.http.client.AsyncHttpClientConfigBean doesn't use com.ning.http.client.AsyncHttpClientConfig.Builder thus doesn't pick many default values, unluckily maxConnectionLifeTimeInMs is one of them, it's wrongly initialized to zero instead of -1, this bug will make org.asynchttpclient.providers.netty.channel.DefaultChannelPool.offer() close the cached http connection too early because "createTime + maxConnectionLifeTimeInMs < millisTime()". public boolean offer(String uri, Channel channel) { if (closed.get()) 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); return false; } --- .../java/org/asynchttpclient/AsyncHttpClientConfigBean.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index f5042b37d3..394fe1aabc 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -51,6 +51,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"); @@ -99,6 +100,11 @@ public AsyncHttpClientConfigBean setConnectionTimeOutInMs(int connectionTimeOutI return this; } + public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { + this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + return this; + } + public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; return this; From bdaddbc57234f9e650f4dc87b85bb1e464e3764b Mon Sep 17 00:00:00 2001 From: Yubao Liu Date: Mon, 21 Apr 2014 18:41:25 +0800 Subject: [PATCH 0055/2070] enable customization of strict302Handling in AsyncHttpClientConfigBean need this method for Spring bean configuration --- .../java/org/asynchttpclient/AsyncHttpClientConfigBean.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 394fe1aabc..e0e01b9943 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -130,6 +130,11 @@ public AsyncHttpClientConfigBean setMaxDefaultRedirects(int maxDefaultRedirects) return this; } + public AsyncHttpClientConfigBean setStrict302Handling(boolean strict302Handling) { + this.strict302Handling = strict302Handling; + return this; + } + public AsyncHttpClientConfigBean setCompressionEnabled(boolean compressionEnabled) { this.compressionEnabled = compressionEnabled; return this; From 0f5397d7291155917b2ec75c85fa07e41e4af0a4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Apr 2014 11:25:00 +0200 Subject: [PATCH 0056/2070] Bump 1.8.8 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab674947c3..6b27e4180d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.7 + 1.8.8 ``` From 9aba8ca3c6b28f14ccd93112a33db79c4e2f01ad Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Apr 2014 21:49:53 +0200 Subject: [PATCH 0057/2070] Upgrade Netty 4.0.19 #546 --- providers/netty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index 296cf8819d..3ecc938d35 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,7 +39,7 @@ io.netty netty-all - 4.0.15.Final + 4.0.19.Final org.javassist From 54869e733b3c5da8fc939192ce806e8ebff20b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20R=C3=A9mond?= Date: Tue, 6 May 2014 13:50:48 +0200 Subject: [PATCH 0058/2070] Uniformized timeout message --- .../netty/request/timeout/RequestTimeoutTimerTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 98c5198895..0044de23da 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -47,7 +47,7 @@ public void run(Timeout timeout) throws Exception { if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { long age = millisTime() - nettyResponseFuture.getStart(); expire("Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " - + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + age + " ms", age); + + nettyResponseFuture.getRequestTimeoutInMs() + " ms", age); nettyResponseFuture.setRequestTimeoutReached(); } } From cc3d57f2b0f29f569bf5415ce0ee29bd86f3c9c0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 6 May 2014 15:43:34 +0200 Subject: [PATCH 0059/2070] Have idle timeout also expose remote ip, just like request timeout #548 --- .../netty/request/timeout/IdleConnectionTimeoutTimerTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java index 99ef4bf1dd..25a9d17dd8 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java @@ -57,8 +57,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) { From 3b4aa0c2f2907ee05ab3ccfbcfcd4dee4de5197b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 6 May 2014 15:44:37 +0200 Subject: [PATCH 0060/2070] minor clean up --- .../netty/request/timeout/RequestTimeoutTimerTask.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 0044de23da..6035974823 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -45,9 +45,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", age); + expire(message, age); nettyResponseFuture.setRequestTimeoutReached(); } } From 368fb5753715f88d78e5c347d2fc8a9f1b2b0bb7 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 14 May 2014 23:30:20 -0700 Subject: [PATCH 0061/2070] [master] + integrate Grizzly 2.3.12 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 44 ++- .../filters/AsyncHttpClientFilter.java | 8 +- .../GrizzlyFeedableBodyGeneratorTest.java | 292 ++++++++++++++++++ 3 files changed, 325 insertions(+), 19 deletions(-) create mode 100644 providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 722a1b7e88..6949ca9be3 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.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. @@ -73,6 +73,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.glassfish.grizzly.spdy.SpdyVersion; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -441,8 +442,9 @@ void timeout(final Connection c) { // ---------------------------------------------------------- Nested Classes private static final class ProtocolNegotiator implements ClientSideNegotiator { + private static final SpdyVersion[] SUPPORTED_SPDY_VERSIONS = + {SpdyVersion.SPDY_3_1, SpdyVersion.SPDY_3}; - private static final String SPDY = "spdy/3"; private static final String HTTP = "HTTP/1.1"; private final FilterChain spdyFilterChain; @@ -465,23 +467,31 @@ public boolean wantNegotiate(SSLEngine engine) { } @Override - public String selectProtocol(SSLEngine engine, LinkedHashSet strings) { - GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selectProtocol: " + strings); + public String selectProtocol(SSLEngine engine, LinkedHashSet protocols) { + GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selectProtocol: " + protocols); final Connection connection = NextProtoNegSupport.getConnection(engine); - // Give preference to SPDY/3. If not available, check for HTTP as a - // fallback - if (strings.contains(SPDY)) { - GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selecting: " + SPDY); - SSLConnectionContext sslCtx = SSLUtils.getSslConnectionContext(connection); - sslCtx.setNewConnectionFilterChain(spdyFilterChain); - final SpdySession spdySession = new SpdySession(connection, false, spdyHandlerFilter); - spdySession.setLocalInitialWindowSize(spdyHandlerFilter.getInitialWindowSize()); - spdySession.setLocalMaxConcurrentStreams(spdyHandlerFilter.getMaxConcurrentStreams()); - Utils.setSpdyConnection(connection); - SpdySession.bind(connection, spdySession); - return SPDY; - } else if (strings.contains(HTTP)) { + // Give preference to SPDY/3.1 or SPDY/3. If not available, check for HTTP as a + // fallback + for (SpdyVersion version : SUPPORTED_SPDY_VERSIONS) { + final String versionDef = version.toString(); + if (protocols.contains(versionDef)) { + GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selecting: " + versionDef); + SSLConnectionContext sslCtx = SSLUtils.getSslConnectionContext(connection); + sslCtx.setNewConnectionFilterChain(spdyFilterChain); + final SpdySession spdySession = + version.newSession(connection, false, spdyHandlerFilter); + + spdySession.setLocalStreamWindowSize(spdyHandlerFilter.getInitialWindowSize()); + spdySession.setLocalMaxConcurrentStreams(spdyHandlerFilter.getMaxConcurrentStreams()); + Utils.setSpdyConnection(connection); + SpdySession.bind(connection, spdySession); + + return versionDef; + } + } + + if (protocols.contains(HTTP)) { GrizzlyAsyncHttpProvider.LOGGER.info("ProtocolSelector::selecting: " + HTTP); // Use the default HTTP FilterChain. return HTTP; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 490e38776d..53647c84d4 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -281,8 +281,9 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, sendingCtx = checkAndHandleFilterChainUpdate(ctx, sendingCtx); } final Connection c = ctx.getConnection(); + final HttpContext httpCtx; if (!Utils.isSpdyConnection(c)) { - HttpContext.newInstance(ctx, c, c, c); + httpCtx = HttpContext.newInstance(c, c, c, requestPacketLocal); } else { SpdySession session = SpdySession.get(c); final Lock lock = session.getNewClientStreamLock(); @@ -290,12 +291,15 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, lock.lock(); SpdyStream stream = session.openStream(requestPacketLocal, session.getNextLocalStreamId(), 0, 0, 0, false, !requestPacketLocal.isExpectContent()); - HttpContext.newInstance(ctx, stream, stream, stream); + httpCtx = HttpContext.newInstance(stream, stream, stream, requestPacketLocal); } finally { lock.unlock(); } } + httpCtx.attach(ctx); HttpTxContext.set(ctx, httpTxContext); + requestPacketLocal.getProcessingState().setHttpContext(httpCtx); + return sendRequest(sendingCtx, request, requestPacketLocal); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java new file mode 100644 index 0000000000..b80e6b724e --- /dev/null +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -0,0 +1,292 @@ +/* + * 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 org.asynchttpclient.providers.grizzly; + +import org.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.RequestBuilder; +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 org.asynchttpclient.DefaultAsyncHttpClient; + +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 = 10; + 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 DefaultAsyncHttpClient(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 org.asynchttpclient.Response onCompleted(org.asynchttpclient.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 aaf7c17531618f8e075c98d0acf0c8cf42d92661 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 15 May 2014 00:58:07 -0700 Subject: [PATCH 0062/2070] [master] 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" --- .../providers/grizzly/EventHandler.java | 7 ++-- .../grizzly/GrizzlyResponseStatus.java | 14 ++++++- .../providers/grizzly/HttpTxContext.java | 27 ++++++++++-- .../filters/AsyncHttpClientEventFilter.java | 28 ++++++++++++- .../filters/AsyncHttpClientFilter.java | 3 +- .../filters/events/GracefulCloseEvent.java | 41 +++++++++++++++++++ 6 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/GracefulCloseEvent.java diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 2971f0a59c..fe956e4d79 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.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. @@ -163,8 +163,9 @@ public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) { } } } - final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, context.getRequest() - .getURI(), config); + final GrizzlyResponseStatus responseStatus = + new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, + context.getRequest().getURI(), config); context.setResponseStatus(responseStatus); if (context.getStatusHandler() != null) { return; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java index 65eb7dd1ad..8aa2e02cb4 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/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. @@ -38,7 +38,8 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { private final int majorVersion; private final int minorVersion; private final String protocolText; - + private final HttpResponsePacket response; + // ------------------------------------------------------------ Constructors public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, AsyncHttpClientConfig config) { @@ -49,6 +50,8 @@ public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, A majorVersion = response.getProtocol().getMajorVersion(); minorVersion = response.getProtocol().getMinorVersion(); protocolText = response.getProtocolString(); + + this.response = response; } // ----------------------------------------- Methods from HttpResponseStatus @@ -105,4 +108,11 @@ public int getProtocolMinorVersion() { public String getProtocolText() { return protocolText; } + + /** + * @return internal Grizzly {@link HttpResponsePacket} + */ + public HttpResponsePacket getResponse() { + return response; + } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index 8ca71b1ce3..72755014c7 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.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. @@ -33,6 +33,10 @@ import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent; +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.filterchain.FilterChain; +import org.glassfish.grizzly.http.HttpResponsePacket; public final class HttpTxContext { @@ -62,10 +66,21 @@ public final class HttpTxContext { private HandShake handshake; private ProtocolHandler protocolHandler; private WebSocket webSocket; - private CloseListener listener = new CloseListener() { + private final CloseListener listener = new CloseListener() { @Override public void onClosed(Closeable closeable, CloseType type) throws IOException { - if (CloseType.REMOTELY.equals(type)) { + 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(HttpTxContext.this), null); + } else if (CloseType.REMOTELY.equals(type)) { abort(AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); } } @@ -252,6 +267,12 @@ public void setWebSocket(WebSocket webSocket) { this.webSocket = webSocket; } + private boolean isGracefullyFinishResponseOnClose() { + final HttpResponsePacket response = responseStatus.getResponse(); + return !response.getProcessingState().isKeepAlive() && + !response.isChunked() && response.getContentLength() == -1; + } + // ------------------------------------------------- Package Private Methods public HttpTxContext copy() { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java index 4de61df7d7..077437dd7b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.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. @@ -21,6 +21,10 @@ import org.glassfish.grizzly.http.HttpHeader; import java.io.IOException; +import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent; +import org.glassfish.grizzly.filterchain.FilterChainEvent; +import org.glassfish.grizzly.filterchain.NextAction; +import org.glassfish.grizzly.http.HttpResponsePacket; /** * Extension of the {@link HttpClientFilter} that is responsible for handling @@ -45,6 +49,28 @@ public AsyncHttpClientEventFilter(final EventHandler eventHandler, final int max this.eventHandler = eventHandler; } + @Override + 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() + .getResponseStatus().getResponse(); + response.getProcessingState().getHttpContext().attach(ctx); + + onHttpPacketParsed(response, ctx); + + return ctx.getStopAction(); + } + + return ctx.getInvokeAction(); + } + + @Override public void exceptionOccurred(FilterChainContext ctx, Throwable error) { eventHandler.exceptionOccurred(ctx, error); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 53647c84d4..951a206951 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.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. @@ -299,6 +299,7 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, httpCtx.attach(ctx); HttpTxContext.set(ctx, httpTxContext); requestPacketLocal.getProcessingState().setHttpContext(httpCtx); + requestPacketLocal.setConnection(c); return sendRequest(sendingCtx, request, requestPacketLocal); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/GracefulCloseEvent.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/GracefulCloseEvent.java new file mode 100644 index 0000000000..35252b610b --- /dev/null +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/GracefulCloseEvent.java @@ -0,0 +1,41 @@ +/* + * 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 org.asynchttpclient.providers.grizzly.filters.events; + +import org.asynchttpclient.providers.grizzly.HttpTxContext; +import org.glassfish.grizzly.filterchain.FilterChainEvent; + +/** + * {@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 class GracefulCloseEvent implements FilterChainEvent { + private final HttpTxContext httpTxContext; + + public GracefulCloseEvent(HttpTxContext httpTxContext) { + this.httpTxContext = httpTxContext; + } + + public HttpTxContext getHttpTxContext() { + return httpTxContext; + } + + @Override + public Object type() { + return GracefulCloseEvent.class; + } +} From 441d7188cf8abfb0c911a3235e18a2011e6f5b65 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 15 May 2014 01:10:57 -0700 Subject: [PATCH 0063/2070] [master] (forgot to add files) 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" --- providers/grizzly/pom.xml | 8 +- .../GrizzlyNoTransferEncodingTest.java | 108 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java diff --git a/providers/grizzly/pom.xml b/providers/grizzly/pom.xml index decae40aaf..678b60f7c7 100644 --- a/providers/grizzly/pom.xml +++ b/providers/grizzly/pom.xml @@ -14,7 +14,7 @@ - 2.3.11 + 2.3.12 1.1 @@ -39,6 +39,12 @@ grizzly-npn-api ${grizzly.npn.version} + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + test + diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java new file mode 100644 index 0000000000..d3b796fc0e --- /dev/null +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/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 org.asynchttpclient.providers.grizzly; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import org.asynchttpclient.DefaultAsyncHttpClient; +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.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; + +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 DefaultAsyncHttpClient( + new GrizzlyAsyncHttpProvider(config), config); + + try { + Future f = client.prepareGet(url).execute(); + org.asynchttpclient.Response r = f.get(10, TimeUnit.SECONDS); + Assert.assertEquals(TEST_MESSAGE, r.getResponseBody()); + } finally { + client.close(); + } + } +} From ce46444e903a4b41906fa7224f0496a1c7a3ff25 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 15 May 2014 23:06:20 -0700 Subject: [PATCH 0064/2070] [master] fix issue #499 (not all the proposed changes are taken) https://github.com/AsyncHttpClient/async-http-client/pull/499 "NonBlockingFeeder improvements" --- .../grizzly/FeedableBodyGenerator.java | 93 +++++++---- .../GrizzlyFeedableBodyGeneratorTest.java | 147 +++++++++++++++++- 2 files changed, 211 insertions(+), 29 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java index cd6e52bb23..1717dcba18 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/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. @@ -24,11 +24,14 @@ import org.glassfish.grizzly.OutputSink; 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.HttpContext; 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.threadpool.Threads; import org.glassfish.grizzly.utils.Futures; @@ -36,6 +39,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.ExecutionException; +import static org.glassfish.grizzly.ssl.SSLUtils.getSSLEngine; + /** * {@link BodyGenerator} which may return just part of the payload at the time * handler is requesting it. If it happens - PartialBodyGenerator becomes responsible @@ -159,10 +164,14 @@ public synchronized void initializeAsynchronousTransfer(final FilterChainContext @Override public void run() { try { - feeder.flush(); + if (requestPacket.isSecure() && + (getSSLEngine(context.getConnection()) == null)) { + flushOnSSLHandshakeComplete(); + } else { + feeder.flush(); + } } catch (IOException ioe) { - HttpTxContext ctx = HttpTxContext.get(context); - ctx.abort(ioe); + throwError(ioe); } } }; @@ -183,6 +192,36 @@ private boolean isServiceThread() { return Threads.isService(); } + + 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); + final Connection c = context.getConnection(); + filter.addHandshakeListener(new SSLBaseFilter.HandshakeListener() { + public void onStart(Connection connection) { + } + + public void onComplete(Connection connection) { + if (c.equals(connection)) { + filter.removeHandshakeListener(this); + try { + feeder.flush(); + } catch (IOException ioe) { + throwError(ioe); + } + } + } + }); + filter.handshake(context.getConnection(), null); + } + + private void throwError(final Throwable t) { + HttpTxContext httpTxContext = HttpTxContext.get(context); + httpTxContext.abort(t); + } + // ----------------------------------------------------------- Inner Classes private final class EmptyBody implements Body { @@ -410,7 +449,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, @@ -441,16 +480,15 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { * {@inheritDoc} */ @Override - public synchronized void flush() { + public synchronized void flush() throws IOException { final HttpContext httpContext = HttpContext.get(feedableBodyGenerator.context); final OutputSink outputSink = httpContext.getOutputSink(); if (isReady()) { - writeUntilFullOrDone(outputSink); + final boolean notReady = writeUntilFullOrDone(outputSink); if (!isDone()) { - if (!isReady()) { + if (notReady) { notifyReadyToFeed(new ReadyToFeedListenerImpl()); - } - if (!outputSink.canWrite()) { + } else { // write queue is full, leverage WriteListener to let us know // when it is safe to write again. outputSink.notifyCanWrite(new WriteHandlerImpl()); @@ -463,15 +501,17 @@ public synchronized void flush() { // ----------------------------------------------------- Private Methods - private void writeUntilFullOrDone(final OutputSink outputSink) { + private boolean writeUntilFullOrDone(final OutputSink outputSink) + throws IOException { while (outputSink.canWrite()) { if (isReady()) { canFeed(); - } - if (!isReady()) { - break; + } else { + return true; } } + + return false; } // ------------------------------------------------------- Inner Classes @@ -505,17 +545,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 @@ -523,8 +553,7 @@ public void onError(Throwable t) { if (!Utils.isSpdyConnection(c)) { c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); } - HttpTxContext httpTxContext = HttpTxContext.get(ctx); - httpTxContext.abort(t); + feedableBodyGenerator.throwError(t); } } // END WriteHandlerImpl @@ -535,7 +564,15 @@ private final class ReadyToFeedListenerImpl implements NonBlockingFeeder.ReadyTo @Override public void ready() { - flush(); + try { + flush(); + } catch (IOException e) { + final Connection c = feedableBodyGenerator.context.getConnection(); + if (!Utils.isSpdyConnection(c)) { + c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); + } + feedableBodyGenerator.throwError(e); + } } } // END ReadToFeedListenerImpl diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index b80e6b724e..400ca9192d 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/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. @@ -43,6 +43,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.asynchttpclient.DefaultAsyncHttpClient; +import org.asynchttpclient.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder; import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; import static org.glassfish.grizzly.memory.MemoryManager.DEFAULT_MEMORY_MANAGER; @@ -114,6 +115,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 @@ -220,7 +230,142 @@ 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 DefaultAsyncHttpClient(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 org.asynchttpclient.Response onCompleted(org.asynchttpclient.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 { final SSLContextConfigurator sslContextConfigurator = From 64140b52a44ae7ea10721b22fe72c4eb32847a0e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 16 May 2014 15:45:42 +0200 Subject: [PATCH 0065/2070] Fix test: http://google.com/ now replies with 302 instead of 301 --- api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index 521ce1d6bc..a6e08a2111 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -119,7 +119,7 @@ public void testGoogleComWithTimeout() throws Exception { 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 1ec309268bbed966214ce1a4f3880f48d0ca25e3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 16 May 2014 15:47:33 +0200 Subject: [PATCH 0066/2070] Fix test: http://google.com/ now replies with 302 instead of 301 --- .../java/org/asynchttpclient/async/AsyncStreamHandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 610f521cae..b38319e800 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -347,7 +347,7 @@ public void asyncStream301WithBody() throws Exception { c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { - assertEquals(301, status.getStatusCode()); + assertEquals(302, status.getStatusCode()); return STATE.CONTINUE; } From d2e455e388100eeb4075c8c338cc7be287373351 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 16 May 2014 16:37:13 +0200 Subject: [PATCH 0067/2070] Clean up damn tests --- .../async/AsyncStreamHandlerTest.java | 272 +++++++++--------- 1 file changed, 129 insertions(+), 143 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index b38319e800..80838a4f7e 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -18,12 +18,14 @@ import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; 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.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; @@ -32,15 +34,12 @@ 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 { @@ -50,15 +49,15 @@ public abstract class AsyncStreamHandlerTest extends AbstractBasicTest { 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 { c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { try { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } finally { l.countDown(); @@ -68,7 +67,7 @@ public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @Override public void onThrowable(Throwable t) { try { - fail("", t); + throwable.set(t); } finally { l.countDown(); } @@ -78,6 +77,12 @@ public void onThrowable(Throwable t) { if (!l.await(5, TimeUnit.SECONDS)) { fail("Timeout out"); } + + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "No response headers"); + assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET, "Unexpected content-type"); + assertNull(throwable.get(), "Unexpected exception"); + } finally { c.close(); } @@ -85,22 +90,20 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider" }) public void asyncStreamPOSTTest() throws Exception { - 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 AtomicReference responseHeaders = new AtomicReference(); AsyncHttpClient c = getAsyncHttpClient(null); try { - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + 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(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -112,19 +115,16 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } + return builder.toString().trim(); } }); - if (!l.await(10, TimeUnit.SECONDS)) { - fail("Timeout out"); - } + String responseBody = f.get(10, TimeUnit.SECONDS); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h); + assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + assertEquals(responseBody, RESPONSE); + } finally { c.close(); } @@ -133,44 +133,44 @@ public String onCompleted() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void asyncStreamInterruptTest() throws Exception { 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); AsyncHttpClient c = getAsyncHttpClient(null); + + final AtomicReference responseHeaders = new AtomicReference(); + final AtomicBoolean bodyReceived = new AtomicBoolean(false); + final AtomicReference throwable = new AtomicReference(); try { - c.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(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } @Override public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { - a.set(false); - fail("Interrupted not working"); + bodyReceived.set(true); return STATE.ABORT; } @Override public void onThrowable(Throwable t) { - try { - fail("", t); - } finally { - l.countDown(); - } + throwable.set(t); + l.countDown(); } }); l.await(5, TimeUnit.SECONDS); - 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", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH), "Unexpected content-type"); + assertNull(throwable.get(), "Should get an exception"); + } finally { c.close(); } @@ -178,18 +178,16 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider" }) public void asyncStreamFutureTest() throws Exception { - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + final AtomicReference throwable = new AtomicReference(); try { - Future f = c.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(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -201,24 +199,23 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - String r = builder.toString().trim(); - assertEquals(r, RESPONSE); - return r; + return builder.toString().trim(); } @Override public void onThrowable(Throwable t) { - fail("", t); + throwable.set(t); } }); - try { - String r = f.get(5, TimeUnit.SECONDS); - assertNotNull(r); - assertEquals(r.trim(), RESPONSE); - } catch (TimeoutException ex) { - fail(); - } + String responseBody = f.get(5, TimeUnit.SECONDS); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH), "Unexpected content-type"); + assertNotNull(responseBody, "No response body"); + assertEquals(responseBody.trim(), RESPONSE, "Unexpected response body"); + assertNull(throwable.get(), "Unexpected exception"); + } finally { c.close(); } @@ -259,22 +256,20 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider" }) public void asyncStreamReusePOSTTest() throws Exception { - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); try { - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + 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(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -286,30 +281,26 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } - + return builder.toString(); } }); - if (!l.await(20, TimeUnit.SECONDS)) { - 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", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH), "Unexpected content-type"); + assertNotNull(r, "No response body"); + assertEquals(r.trim(), RESPONSE, "Unexpected response body"); + + responseHeaders.set(null); // Let do the same again - c.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(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", "), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -321,41 +312,37 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } + return builder.toString(); } }); - if (!l.await(20, TimeUnit.SECONDS)) { - fail("Timeout out"); - } + f.get(5, TimeUnit.SECONDS); + h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH), "Unexpected content-type"); + assertNotNull(r, "No response body"); + assertEquals(r.trim(), RESPONSE, "Unexpected response body"); } finally { c.close(); } } @Test(groups = { "online", "default_provider" }) - public void asyncStream301WithBody() throws Exception { - final CountDownLatch l = new CountDownLatch(1); + public void asyncStream302WithBody() throws Exception { AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference statusCode = new AtomicReference(0); + final AtomicReference headers = new AtomicReference(); try { - c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { - assertEquals(302, status.getStatusCode()); + statusCode.set(status.getStatusCode()); return STATE.CONTINUE; } @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH)); + headers.set(content.getHeaders()); return STATE.CONTINUE; } @@ -366,57 +353,59 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - l.countDown(); return null; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - 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 { c.close(); } } @Test(groups = { "online", "default_provider" }) - public void asyncStream301RedirectWithBody() throws Exception { - final CountDownLatch l = new CountDownLatch(1); + 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 { - c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { - assertTrue(status.getStatusCode() != 301); + statusCode.set(status.getStatusCode()); return STATE.CONTINUE; } @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - 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"); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @Override public String onCompleted() throws Exception { - l.countDown(); return null; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - 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 { c.close(); } @@ -493,37 +482,34 @@ public Integer onCompleted() throws Exception { @Test(groups = { "online", "default_provider" }) public void asyncOptionsTest() throws Exception { - final CountDownLatch l = new CountDownLatch(1); AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + try { final String[] expected = { "GET", "HEAD", "OPTIONS", "POST", "TRACE" }; - c.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { + Future f = c.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - assertNotNull(h); - String[] values = h.get("Allow").get(0).split(",|, "); - assertNotNull(values); - assertEquals(values.length, expected.length); - Arrays.sort(values); - assertEquals(values, expected); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } @Override public String onCompleted() throws Exception { - try { - return "OK"; - } finally { - l.countDown(); - } + return "OK"; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - 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 { c.close(); } From 1e9ae842ca94f326215358917c620ac407323c81 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 11:20:25 +0200 Subject: [PATCH 0068/2070] Make SignatureCalculator available on RequestBuilderBase, close #557 --- .../asynchttpclient/BoundRequestBuilder.java | 31 ++----------------- .../asynchttpclient/RequestBuilderBase.java | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java index 7dacfb6cd3..b42f2e2eae 100644 --- a/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java +++ b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java @@ -24,18 +24,6 @@ public class BoundRequestBuilder extends RequestBuilderBase private final AsyncHttpClient client; - /** - * 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; - public BoundRequestBuilder(AsyncHttpClient client, String reqType, boolean useRawUrl) { super(BoundRequestBuilder.class, reqType, useRawUrl); this.client = client; @@ -85,18 +73,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(); } @@ -142,7 +118,6 @@ public BoundRequestBuilder setParameters(FluentStringsMap parameters) { @Override public BoundRequestBuilder setUrl(String url) { - baseURL = url; return super.setUrl(url); } @@ -151,8 +126,8 @@ public BoundRequestBuilder setVirtualHost(String virtualHost) { return super.setVirtualHost(virtualHost); } + @Override public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureCalculator) { - this.signatureCalculator = signatureCalculator; - return this; + return super.setSignatureCalculator(signatureCalculator); } -} \ No newline at end of file +} diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index cd4cd2df1d..3b8fbfe04c 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -357,6 +357,17 @@ public boolean isUseRawUrl() { private final Class derived; protected final RequestImpl request; protected boolean useRawUrl = false; + /** + * 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; protected RequestBuilderBase(Class derived, String method, boolean rawUrls) { this.derived = derived; @@ -372,6 +383,7 @@ protected RequestBuilderBase(Class derived, Request prototype) { } public T setUrl(String url) { + baseURL = url; return setURI(URI.create(url)); } @@ -424,6 +436,11 @@ public T setVirtualHost(String virtualHost) { return derived.cast(this); } + public T setSignatureCalculator(SignatureCalculator signatureCalculator) { + this.signatureCalculator = signatureCalculator; + return derived.cast(this); + } + public T setHeader(String name, String value) { request.getHeaders().replace(name, value); return derived.cast(this); @@ -615,6 +632,20 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe } 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 >= 0) { + url = url.substring(0, i); + } + signatureCalculator.calculateAndAddSignature(url, request, this); + } + if (request.length < 0 && request.streamData == null) { // can't concatenate content-length String contentLength = null; From 04e256ce9571e4239403b657126ce8eb30ad6776 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:38:45 +0200 Subject: [PATCH 0069/2070] Introduce Realm useAbsoluteURI and omitQuery, close #553 --- .../main/java/org/asynchttpclient/Realm.java | 52 +++++++++++++++---- .../providers/netty/handler/HttpProtocol.java | 25 ++++++++- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index cf2e07a3f6..3214651fac 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -50,6 +50,8 @@ public class Realm { private final boolean messageType2Received; private final String domain; private final Charset charset; + private final boolean useAbsoluteURI; + private final boolean omitQuery; public enum AuthScheme { DIGEST, BASIC, NTLM, SPNEGO, KERBEROS, NONE @@ -57,7 +59,7 @@ public enum AuthScheme { private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, String qop, String nc, String cnonce, String uri, String method, boolean usePreemptiveAuth, String domain, String enc, - String host, boolean messageType2Received, String opaque) { + String host, boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery) { this.principal = principal; this.password = password; @@ -78,6 +80,8 @@ private Realm(AuthScheme scheme, String principal, String password, String realm this.host = host; this.messageType2Received = messageType2Received; this.charset = enc != null ? Charset.forName(enc) : null; + this.useAbsoluteURI = useAbsoluteURI; + this.omitQuery = omitQuery; } public String getPrincipal() { @@ -176,6 +180,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) @@ -207,7 +219,8 @@ public boolean equals(Object o) { 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; } @@ -215,7 +228,8 @@ public boolean equals(Object o) { public String toString() { return "Realm{" + "principal='" + principal + '\'' + ", scheme=" + scheme + ", realmName='" + realmName + '\'' + ", nonce='" + nonce + '\'' + ", algorithm='" + algorithm + '\'' + ", response='" + response + '\'' + ", qop='" + qop + '\'' + ", nc='" - + nc + '\'' + ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' + ", methodName='" + methodName + '\'' + '}'; + + nc + '\'' + ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' + ", methodName='" + methodName + '\'' + ", useAbsoluteURI='" + useAbsoluteURI + '\'' + + ", omitQuery='" + omitQuery + '\'' +'}'; } @Override @@ -261,6 +275,8 @@ public static class RealmBuilder { private String enc = StandardCharsets.UTF_8.name(); private String host = "localhost"; private boolean messageType2Received = false; + private boolean useAbsoluteURI = true; + private boolean omitQuery = false; public String getNtlmDomain() { return domain; @@ -397,6 +413,29 @@ public RealmBuilder setUsePreemptiveAuth(boolean usePreemptiveAuth) { return this; } + public RealmBuilder setNtlmMessageType2Received(boolean messageType2Received) { + this.messageType2Received = messageType2Received; + 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")); @@ -427,11 +466,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()); @@ -574,7 +608,7 @@ public Realm build() { } return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName, - usePreemptive, domain, enc, host, messageType2Received, opaque); + usePreemptive, domain, enc, host, messageType2Received, opaque, useAbsoluteURI, omitQuery); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 032a3d9ae1..0845fe9691 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -61,6 +61,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.util.List; final class HttpProtocol extends Protocol { @@ -202,6 +203,27 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) th } } + private final String computeRealmURI(Realm realm, URI requestURI) throws URISyntaxException { + if (realm.isUseAbsoluteURI()) { + if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { + return new URI( + requestURI.getScheme(), + requestURI.getAuthority(), + requestURI.getPath(), + null, + null).toString(); + } else { + return requestURI.toString(); + } + } else { + if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { + return requestURI.getPath(); + } else { + return requestURI.getPath() + "?" + requestURI.getQuery(); + } + } + } + private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws Exception { if (statusCode == UNAUTHORIZED.code() && realm != null) { @@ -227,7 +249,8 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req .parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); } - Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(request.getURI().getPath()).build(); + String realmURI = computeRealmURI(newRealm, request.getURI()); + Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); LOGGER.debug("Sending authentication to {}", request.getUrl()); From 3c56c7f883a0c39196cf11d1d190811331e9b9d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 16:07:09 +0200 Subject: [PATCH 0070/2070] Advertise 1.8.9 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b27e4180d..5a09dc329a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.8 + 1.8.9 ``` From e84ee123f57958fc0cd8f7f2b1df195ec68f94d1 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 20 May 2014 22:43:55 -0700 Subject: [PATCH 0071/2070] [master] + fix the issue #559 https://github.com/AsyncHttpClient/async-http-client/issues/559 GrizzlyAsyncHttpProvider hangs on Exception #559 --- .../providers/grizzly/EventHandler.java | 10 +++++++--- .../grizzly/filters/AsyncHttpClientEventFilter.java | 5 +++++ .../grizzly/filters/AsyncSpdyClientEventFilter.java | 8 +++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index fe956e4d79..6f7a6280df 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -196,10 +196,14 @@ public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) { public void onHttpHeaderError(final HttpHeader httpHeader, final FilterChainContext ctx, final Throwable t) { - t.printStackTrace(); httpHeader.setSkipRemainder(true); - final HttpTxContext context = HttpTxContext.get(ctx); - context.abort(t); + HttpTxContext.get(ctx).abort(t); + } + + public void onHttpContentError(final HttpHeader httpHeader, final FilterChainContext ctx, final Throwable t) { + + httpHeader.setSkipRemainder(true); + HttpTxContext.get(ctx).abort(t); } @SuppressWarnings({ "unchecked" }) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java index 077437dd7b..6afb87197a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java @@ -101,6 +101,11 @@ protected void onHttpHeaderError(HttpHeader httpHeader, FilterChainContext ctx, eventHandler.onHttpHeaderError(httpHeader, ctx, t); } + @Override + protected void onHttpContentError(HttpHeader httpHeader, FilterChainContext ctx, Throwable t) throws IOException { + eventHandler.onHttpContentError(httpHeader, ctx, t); + } + @Override protected void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { eventHandler.onHttpHeadersParsed(httpHeader, ctx); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java index 98a5f823b3..758c6e7783 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncSpdyClientEventFilter.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. @@ -72,6 +72,12 @@ protected void onHttpHeaderError(HttpHeader httpHeader, FilterChainContext ctx, eventHandler.onHttpHeaderError(httpHeader, ctx, t); } + @Override + protected void onHttpContentError(HttpHeader httpHeader, FilterChainContext ctx, Throwable t) throws IOException { + eventHandler.onHttpContentError(httpHeader, ctx, t); + } + + @Override protected void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { eventHandler.onHttpHeadersParsed(httpHeader, ctx); From fc71f653a056f2bf4404b3d3934d446ec69535fe Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 22 May 2014 18:12:34 -0700 Subject: [PATCH 0072/2070] [master] + minor updates --- .../providers/grizzly/EventHandler.java | 3 +-- .../providers/grizzly/HttpTxContext.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 6f7a6280df..ec251b8955 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -379,8 +379,7 @@ private static boolean isRedirectAllowed(final HttpTxContext ctx) { private static HttpTxContext cleanup(final FilterChainContext ctx) { final Connection c = ctx.getConnection(); - final HttpTxContext context = HttpTxContext.get(ctx); - HttpTxContext.remove(ctx, context); + final HttpTxContext context = HttpTxContext.remove(ctx); if (!Utils.isSpdyConnection(c) && !Utils.isIgnored(c)) { final ConnectionManager manager = context.getProvider().getConnectionManager(); //if (!manager.canReturnConnection(c)) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index 72755014c7..a12fc65748 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java @@ -69,7 +69,8 @@ public final class HttpTxContext { 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. @@ -107,10 +108,14 @@ public static void set(final FilterChainContext ctx, final HttpTxContext httpTxC REQUEST_STATE_ATTR.set(httpContext, httpTxContext); } - public static void remove(final FilterChainContext ctx, final HttpTxContext httpTxContext) { - HttpContext httpContext = HttpContext.get(ctx); - httpContext.getCloseable().removeCloseListener(httpTxContext.listener); - REQUEST_STATE_ATTR.remove(ctx); + public static HttpTxContext remove(final FilterChainContext ctx) { + final HttpContext httpContext = HttpContext.get(ctx); + final HttpTxContext httpTxContext = REQUEST_STATE_ATTR.remove(httpContext); + if (httpTxContext != null) { + httpContext.getCloseable().removeCloseListener(httpTxContext.listener); + } + + return httpTxContext; } public static HttpTxContext get(FilterChainContext ctx) { From 7dae1e8a2aa9fa7c00a0f66f5afbb014440e3368 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 27 May 2014 13:09:52 -0700 Subject: [PATCH 0073/2070] [master] + integrate Grizzly 2.3.13 --- providers/grizzly/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/grizzly/pom.xml b/providers/grizzly/pom.xml index 678b60f7c7..9de0ff62a0 100644 --- a/providers/grizzly/pom.xml +++ b/providers/grizzly/pom.xml @@ -14,7 +14,7 @@ - 2.3.12 + 2.3.13 1.1 From aaaced7a2e975dce073863ef6e7c8292c216e241 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 3 Jun 2014 11:14:54 +0200 Subject: [PATCH 0074/2070] Port #563 on master --- .../providers/netty/handler/HttpProtocol.java | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 0845fe9691..57f81b6142 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -78,7 +78,7 @@ private Realm.RealmBuilder newRealmBuilder(Realm realm) { } private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { + FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { URI uri = request.getURI(); String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); @@ -96,19 +96,23 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } catch (Throwable throwable) { if (isNTLM(proxyAuth)) { - return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future); + return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); } channels.abort(future, throwable); return null; } } - private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader) { - headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + private String authorizationHeaderName(boolean proxyInd) { + return proxyInd? HttpHeaders.Names.PROXY_AUTHORIZATION: HttpHeaders.Names.AUTHORIZATION; + } + + private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { + headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, - Realm realm, NettyResponseFuture future) throws NTLMEngineException { + Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { boolean useRealm = proxyServer == null && realm != null; @@ -121,7 +125,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); URI uri = request.getURI(); - addNTLMAuthorizationHeader(headers, challengeHeader); + addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); future.getAndSetAuth(false); return newRealmBuilder(realm)// .setScheme(realm.getAuthScheme())// @@ -131,7 +135,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p .build(); } else { - addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost); + addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; return newRealmBuilder(realm)// .setScheme(authScheme)// @@ -142,12 +146,12 @@ 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 { + 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()); + proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd); return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) @@ -156,13 +160,13 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer } private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, - String password, String domain, String workstation) throws NTLMEngineException { - headers.remove(HttpHeaders.Names.AUTHORIZATION); + 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); + addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); } } @@ -236,10 +240,10 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req // NTLM boolean negociate = authenticateHeaders.contains("Negotiate"); if (!authenticateHeaders.contains("Kerberos") && (isNTLM(authenticateHeaders) || negociate)) { - newRealm = ntlmChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future); + newRealm = ntlmChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); // SPNEGO KERBEROS } else if (negociate) { - newRealm = kerberosChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future); + newRealm = kerberosChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); if (newRealm == null) { return true; } @@ -305,10 +309,10 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// boolean negociate = proxyAuthenticateHeaders.contains("Negotiate"); if (!proxyAuthenticateHeaders.contains("Kerberos") && (isNTLM(proxyAuthenticateHeaders) || negociate)) { - newRealm = ntlmProxyChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future); + newRealm = ntlmProxyChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); // SPNEGO KERBEROS } else if (negociate) { - newRealm = kerberosChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future); + newRealm = kerberosChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); if (newRealm == null) return true; } else { @@ -459,10 +463,12 @@ && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest() try { channels.abort(future, t); + } catch (Exception abortException) { + LOGGER.debug("Abort failed", abortException); } finally { finishUpdate(future, channel, false); - throw t; } + throw t; } } From e1e8e34310ff2d1f5e0207d53eaab1b57b4729aa Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 3 Jun 2014 15:47:32 -0400 Subject: [PATCH 0075/2070] New URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a09dc329a..a2c150d501 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You can also download the artifact [Maven Search](http://search.maven.org) -Then in your code you can simply do ([Javadoc](http://sonatype.github.com/async-http-client/apidocs/index.html)) +Then in your code you can simply do [Javadoc](http://asynchttpclient.github.io/async-http-client/apidocs/reference/packages.html) ```java import com.ning.http.client.*; From c90cf8628bdcf1bfca6cb512c08ead143914b82f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 08:51:04 +0200 Subject: [PATCH 0076/2070] Have one central place for configuration defaults, close #565 --- .../AsyncHttpClientConfig.java | 202 ++++++++---------- .../AsyncHttpClientConfigBean.java | 60 +++--- .../AsyncHttpClientConfigDefaults.java | 136 ++++++++++++ .../SimpleAsyncHttpClient.java | 12 +- .../async/AsyncProvidersBasicTest.java | 2 +- .../asynchttpclient/async/BasicAuthTest.java | 2 +- .../asynchttpclient/async/BodyChunkTest.java | 2 +- .../asynchttpclient/async/ChunkingTest.java | 4 +- .../async/ConnectionPoolTest.java | 8 +- .../async/HttpToHttpsRedirectTest.java | 6 +- .../async/MaxConnectionsInThreads.java | 2 +- .../async/MaxTotalConnectionTest.java | 6 +- .../async/NoNullResponseTest.java | 2 +- .../org/asynchttpclient/async/RC10KTest.java | 2 +- .../async/RedirectConnectionUsageTest.java | 4 +- .../asynchttpclient/async/RemoteSiteTest.java | 2 +- .../async/SimpleAsyncHttpClientTest.java | 8 +- .../grizzly/GrizzlyConnectionPoolTest.java | 2 +- .../GrizzlyFeedableBodyGeneratorTest.java | 8 +- .../NettyRequestThrottleTimeoutTest.java | 2 +- .../netty/RetryNonBlockingIssue.java | 5 +- 21 files changed, 290 insertions(+), 187 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index c352c7f43c..babb8cbd9e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -15,13 +15,12 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.getBoolean; +import static org.asynchttpclient.AsyncHttpClientConfigDefaults.*; import org.asynchttpclient.date.TimeConverter; import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.util.DefaultHostnameVerifier; import org.asynchttpclient.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; @@ -46,14 +45,14 @@ * -Dorg.asynchttpclient.AsyncHttpClientConfig.nameOfTheProperty * ex: *

- * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultMaxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultMaxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultMaxConnectionsPerHost - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultConnectionTimeoutInMS - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultIdleConnectionInPoolTimeoutInMS - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultRequestTimeoutInMS - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultRedirectsEnabled - * -Dorg.asynchttpclient.AsyncHttpClientConfig.defaultMaxRedirects + * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections + * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections + * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxConnectionsPerHost + * -Dorg.asynchttpclient.AsyncHttpClientConfig.connectionTimeoutInMs + * -Dorg.asynchttpclient.AsyncHttpClientConfig.idleConnectionInPoolTimeoutInMs + * -Dorg.asynchttpclient.AsyncHttpClientConfig.requestTimeoutInMs + * -Dorg.asynchttpclient.AsyncHttpClientConfig.redirectsEnabled + * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxRedirects */ public class AsyncHttpClientConfig { @@ -88,7 +87,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; @@ -128,7 +127,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // int requestTimeoutInMs, // int connectionMaxLifeTimeInMs, // boolean redirectEnabled, // - int maxDefaultRedirects, // + int maxRedirects, // boolean compressionEnabled, // String userAgent, // boolean keepAlive, // @@ -154,8 +153,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, // boolean spdyEnabled, // int spdyInitialWindowSize, // int spdyMaxConcurrentStreams, // - boolean rfc6265CookieEncoding, // - boolean asyncConnectMode, // TimeConverter timeConverter) { this.maxTotalConnections = maxTotalConnections; @@ -167,7 +164,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; @@ -193,6 +190,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; this.timeConverter = timeConverter; + } /** @@ -274,7 +272,7 @@ public boolean isRedirectEnabled() { * @return the maximum number of HTTP redirect */ public int getMaxRedirects() { - return maxDefaultRedirects; + return maxRedirects; } /** @@ -564,23 +562,34 @@ 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", "AsyncHttpClient/" + AHC_VERSION); - 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 maxRedirects = 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 boolean spdyEnabled = defaultSpdyEnabled(); + private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + private ScheduledExecutorService reaper; private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; @@ -588,22 +597,9 @@ public static class Builder { private SSLEngineFactory sslEngineFactory; private AsyncHttpProviderConfig providerConfig; 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 DefaultHostnameVerifier(); - private int ioThreadMultiplier = 2; - private boolean strict302Handling; - private boolean spdyEnabled; - private int spdyInitialWindowSize = 10 * 1024 * 1024; - private int spdyMaxConcurrentStreams = 100; - private boolean rfc6265CookieEncoding = true; - private boolean asyncConnectMode; private TimeConverter timeConverter; public Builder() { @@ -612,57 +608,57 @@ public Builder() { /** * Set the maximum number of connections an {@link AsyncHttpClient} can handle. * - * @param defaultMaxTotalConnections the maximum number of connections an {@link AsyncHttpClient} can handle. + * @param maxTotalConnections the maximum number of connections an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsTotal(int defaultMaxTotalConnections) { - this.defaultMaxTotalConnections = defaultMaxTotalConnections; + public Builder setMaxConnectionsTotal(int maxTotalConnections) { + this.maxTotalConnections = maxTotalConnections; return this; } /** * Set the maximum number of connections per hosts an {@link AsyncHttpClient} can handle. * - * @param defaultMaxConnectionPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. + * @param maxConnectionPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { - this.defaultMaxConnectionPerHost = defaultMaxConnectionPerHost; + public Builder setMaxConnectionsPerHost(int maxConnectionPerHost) { + this.maxConnectionPerHost = maxConnectionPerHost; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host * - * @param defaultConnectionTimeOutInMs the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host + * @param connectionTimeOutInMs the maximum time in millisecond an {@link 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 org.asynchttpclient.websocket.WebSocket} can stay idle. * - * @param defaultWebSocketIdleTimeoutInMs + * @param webSocketIdleTimeoutInMs * the maximum time in millisecond an {@link org.asynchttpclient.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 AsyncHttpClient} can stay idle. * - * @param defaultIdleConnectionTimeoutInMs + * @param idleConnectionTimeoutInMs * the maximum time in millisecond an {@link 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; } @@ -670,24 +666,24 @@ public Builder setIdleConnectionTimeoutInMs(int defaultIdleConnectionTimeoutInMs * Set the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * idle in pool. * - * @param defaultIdleConnectionInPoolTimeoutInMs + * @param idleConnectionInPoolTimeoutInMs * the maximum time in millisecond an {@link 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 AsyncHttpClient} wait for a response * - * @param defaultRequestTimeoutInMs the maximum time in millisecond an {@link AsyncHttpClient} wait for a response + * @param requestTimeoutInMs the maximum time in millisecond an {@link 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; } @@ -705,11 +701,11 @@ public Builder setFollowRedirects(boolean redirectEnabled) { /** * 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; } @@ -1040,7 +1036,7 @@ public Builder setStrict302Handling(final boolean strict302Handling) { * @return a {@link Builder} */ public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.defaultMaxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; return this; } @@ -1102,34 +1098,6 @@ public Builder setSpdyMaxConcurrentStreams(int spdyMaxConcurrentStreams) { 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; - } - - /** - * Configures how the underlying providers make new connections. By default, - * connections will be made synchronously. - * - * @param asyncConnectMode pass true to enable async connect mode. - * - * @return this - * - * @since 2.0.0 - */ - public Builder setAsyncConnectMode(boolean asyncConnectMode) { - this.asyncConnectMode = asyncConnectMode; - return this; - } - public Builder setTimeConverter(TimeConverter timeConverter) { this.timeConverter = timeConverter; return this; @@ -1143,16 +1111,16 @@ public Builder setTimeConverter(TimeConverter timeConverter) { public Builder(AsyncHttpClientConfig prototype) { allowPoolingConnection = prototype.getAllowPoolingConnection(); providerConfig = prototype.getAsyncHttpProviderConfig(); - defaultConnectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); - defaultIdleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); - defaultIdleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); - defaultMaxConnectionPerHost = prototype.getMaxConnectionPerHost(); - defaultMaxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); - maxDefaultRedirects = prototype.getMaxRedirects(); - defaultMaxTotalConnections = prototype.getMaxTotalConnections(); + connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); + idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); + idleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); + maxConnectionPerHost = prototype.getMaxConnectionPerHost(); + maxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); + maxRedirects = prototype.getMaxRedirects(); + maxTotalConnections = prototype.getMaxTotalConnections(); proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); - defaultRequestTimeoutInMs = prototype.getRequestTimeoutInMs(); + requestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); sslEngineFactory = prototype.getSSLEngineFactory(); userAgent = prototype.getUserAgent(); @@ -1209,16 +1177,16 @@ 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, // + maxRedirects, // compressionEnabled, // userAgent, // allowPoolingConnection, // @@ -1244,8 +1212,6 @@ public Thread newThread(Runnable r) { spdyEnabled, // spdyInitialWindowSize, // spdyMaxConcurrentStreams, // - rfc6265CookieEncoding, // - asyncConnectMode, // timeConverter); } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index e0e01b9943..98ab988ebb 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -12,15 +12,15 @@ */ package org.asynchttpclient; +import static org.asynchttpclient.AsyncHttpClientConfigDefaults.*; + import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.filter.RequestFilter; import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.util.DefaultHostnameVerifier; import org.asynchttpclient.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; import java.util.LinkedList; import java.util.concurrent.ExecutorService; @@ -45,34 +45,36 @@ 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", "AsyncHttpClient/" + AHC_VERSION); - 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(); + spdyEnabled = defaultSpdyEnabled(); + spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + 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 DefaultHostnameVerifier(); } void configureExecutors() { @@ -125,8 +127,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/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java new file mode 100644 index 0000000000..edd51169a1 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -0,0 +1,136 @@ +/* + * 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 org.asynchttpclient; + +import static org.asynchttpclient.util.MiscUtil.getBoolean; + +import org.asynchttpclient.util.DefaultHostnameVerifier; + +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 DefaultHostnameVerifier(); + } + + public static boolean defaultSpdyEnabled() { + return Boolean.getBoolean(ASYNC_CLIENT + "spdyEnabled"); + } + + public static int defaultSpdyInitialWindowSize() { + return Integer.getInteger(ASYNC_CLIENT + "spdyInitialWindowSize", 10 * 1024 * 1024); + } + + public static int defaultSpdyMaxConcurrentStreams() { + return Integer.getInteger(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); + } +} diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 271a352ed6..3bbf84d7fb 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -493,13 +493,13 @@ public Builder setFollowRedirects(boolean followRedirects) { return this; } - public Builder setMaximumConnectionsTotal(int defaultMaxTotalConnections) { - configBuilder.setMaximumConnectionsTotal(defaultMaxTotalConnections); + public Builder setMaxConnectionsTotal(int defaultMaxTotalConnections) { + configBuilder.setMaxConnectionsTotal(defaultMaxTotalConnections); return this; } - public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { - configBuilder.setMaximumConnectionsPerHost(defaultMaxConnectionPerHost); + public Builder setMaxConnectionsPerHost(int defaultMaxConnectionPerHost) { + configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionPerHost); return this; } @@ -518,8 +518,8 @@ public Builder setRequestTimeoutInMs(int defaultRequestTimeoutInMs) { return this; } - public Builder setMaximumNumberOfRedirects(int maxDefaultRedirects) { - configBuilder.setMaximumNumberOfRedirects(maxDefaultRedirects); + public Builder setMaxRedirects(int maxRedirects) { + configBuilder.setMaxRedirects(maxRedirects); return this; } diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index ece7196939..00a1653678 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -1343,7 +1343,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetMaxRedirectTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaximumNumberOfRedirects(0).setFollowRedirects(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaxRedirects(0).setFollowRedirects(true).build()); try { // Use a l in case the assert fail final CountDownLatch l = new CountDownLatch(1); diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 2f5b89073b..bb388d908e 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -197,7 +197,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().setFollowRedirects(true).setMaximumNumberOfRedirects(10).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).setMaxRedirects(10).build()); try { Future f = client.prepareGet(getTargetUrl2())// .setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).build())// diff --git a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java index 917c8a58dd..4dbc04bfb9 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java @@ -36,7 +36,7 @@ public void negativeContentTypeTest() throws Exception { AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); confbuilder = confbuilder.setConnectionTimeoutInMs(100); - confbuilder = confbuilder.setMaximumConnectionsTotal(50); + confbuilder = confbuilder.setMaxConnectionsTotal(50); confbuilder = confbuilder.setRequestTimeoutInMs(5 * 60 * 1000); // 5 minutes // Create client diff --git a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java index 013940ee3c..c590a94a3c 100644 --- a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java @@ -46,8 +46,8 @@ public void testCustomChunking() throws Exception { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsPerHost(1); - bc.setMaximumConnectionsTotal(1); + bc.setMaxConnectionsPerHost(1); + bc.setMaxConnectionsTotal(1); bc.setConnectionTimeoutInMs(1000); bc.setRequestTimeoutInMs(1000); bc.setFollowRedirects(true); diff --git a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java index 792d436d76..be3dc83020 100644 --- a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java @@ -42,7 +42,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().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); try { String url = getTargetUrl(); int i; @@ -64,7 +64,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().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); try { String url = getTargetUrl(); int i; @@ -132,7 +132,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -160,7 +160,7 @@ public void multipleMaxConnectionOpenTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java index 40ebd79f87..f754ac83a5 100644 --- a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java @@ -96,7 +96,7 @@ public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { public void httpToHttpsRedirect() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); @@ -112,7 +112,7 @@ public void httpToHttpsRedirect() throws Exception { public void httpToHttpsProperConfig() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); @@ -134,7 +134,7 @@ public void httpToHttpsProperConfig() throws Exception { public void relativeLocationUrl() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); diff --git a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java index 1d6369762b..31b6ddc359 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java @@ -52,7 +52,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()); + .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); try { final Boolean[] caughtError = new Boolean[] { Boolean.FALSE }; diff --git a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java index d24c61f4a3..245abb9de9 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java @@ -39,7 +39,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().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(1).setMaximumConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); try { boolean caughtError = false; for (int i = 0; i < urls.length; i++) { @@ -61,7 +61,7 @@ public void testMaxTotalConnectionsExceedingException() { public void testMaxTotalConnections() { String[] urls = new String[] { "http://google.com/", "http://lenta.ru/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(2).setMaximumConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(2).setMaxConnectionsPerHost(1).build()); try { for (String url : urls) { try { @@ -82,7 +82,7 @@ public void testMaxTotalConnections() { public void testMaxTotalConnectionsCorrectExceptionHandling() { String[] urls = new String[] { "http://google.com/", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(1).setMaximumConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); try { List> futures = new ArrayList>(); boolean caughtError = false; diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 01411d9906..2b78e7972a 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -57,7 +57,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Exception { private AsyncHttpClient create() throws GeneralSecurityException { final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirects(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) - .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaximumConnectionsPerHost(-1).setMaximumConnectionsTotal(-1); + .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaxConnectionsPerHost(-1).setMaxConnectionsTotal(-1); return getAsyncHttpClient(configBuilder.build()); } diff --git a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java index 64c4e2e8ec..a52ccd4157 100644 --- a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java @@ -99,7 +99,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 ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaximumConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); + AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); try { List> resps = new ArrayList>(C10K); int i = 0; diff --git a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java index 22bdb6b02d..6849615298 100644 --- a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java @@ -75,8 +75,8 @@ public void testGetRedirectFinalUrl() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnection(true)// - .setMaximumConnectionsPerHost(1)// - .setMaximumConnectionsTotal(1)// + .setMaxConnectionsPerHost(1)// + .setMaxConnectionsTotal(1)// .setConnectionTimeoutInMs(1000)// .setRequestTimeoutInMs(1000)// .setFollowRedirects(true)// diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index a6e08a2111..d03c666900 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -155,7 +155,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirects(true) - .setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); + .setAllowPoolingConnection(false).setMaxRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index df07e31922..895144f989 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -49,7 +49,7 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { public void inpuStreamBodyConsumerTest() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + .setMaxConnectionsTotal(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()))); @@ -65,7 +65,7 @@ public void inpuStreamBodyConsumerTest() throws Exception { public void stringBuilderBodyConsumerTest() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + .setMaxConnectionsTotal(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)); @@ -82,7 +82,7 @@ public void stringBuilderBodyConsumerTest() throws Exception { public void byteArrayOutputStreamBodyConsumerTest() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + .setMaxConnectionsTotal(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)); @@ -117,7 +117,7 @@ public void requestByteArrayOutputStreamBodyConsumerTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") .build(); try { File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java index 1beb63e76e..acf6c92a3a 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java @@ -41,7 +41,7 @@ public void testMaxTotalConnectionsException() { @Test public void multipleMaxConnectionOpenTest() throws Exception { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000) - .setMaximumConnectionsTotal(1).build(); + .setMaxConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 400ca9192d..620eb6ea66 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -136,8 +136,8 @@ private void doSimpleFeeder(final boolean secure) { ExecutorService service = Executors.newFixedThreadPool(threadCount); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setMaximumConnectionsPerHost(60) - .setMaximumConnectionsTotal(60) + .setMaxConnectionsPerHost(60) + .setMaxConnectionsTotal(60) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); @@ -238,8 +238,8 @@ private void doNonBlockingFeeder(final boolean secure) { final ExecutorService service = Executors.newCachedThreadPool(); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setMaximumConnectionsPerHost(60) - .setMaximumConnectionsTotal(60) + .setMaxConnectionsPerHost(60) + .setMaxConnectionsTotal(60) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java index 82e39012db..ef02fa7896 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java @@ -82,7 +82,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()); + .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); int samples = 10; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java index ab4fda18b4..de5fbc896e 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java @@ -89,7 +89,7 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, Exe AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnection(true)// - .setMaximumConnectionsTotal(100)// + .setMaxConnectionsTotal(100)// .setConnectionTimeoutInMs(60000)// .setRequestTimeoutInMs(30000)// .build(); @@ -125,10 +125,9 @@ public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedEx AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnection(true)// - .setMaximumConnectionsTotal(100)// + .setMaxConnectionsTotal(100)// .setConnectionTimeoutInMs(60000)// .setRequestTimeoutInMs(30000)// - .setAsyncConnectMode(true) // .build(); AsyncHttpClient client = getAsyncHttpClient(config); From 094fcc01e531c5681fe4b9da6456fd6d11bd9beb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 08:57:36 +0200 Subject: [PATCH 0077/2070] Only trigger IdleChannelDetector when maxIdleTime is > 0, close #566 --- .../providers/netty/channel/DefaultChannelPool.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 3d9fa7fb7f..e4b2554762 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -72,7 +72,9 @@ public DefaultChannelPool(// this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; this.nettyTimer = nettyTimer; - scheduleNewIdleChannelDetector(new IdleChannelDetector()); + if (maxIdleTime > 0L) { + scheduleNewIdleChannelDetector(new IdleChannelDetector()); + } } private void scheduleNewIdleChannelDetector(TimerTask task) { From 9024e4a19aba83cedb813cce82fbdaa5fb68e1ab Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 09:46:21 +0200 Subject: [PATCH 0078/2070] Use Java8 ConcurrentHashMap backport --- .../providers/netty/channel/DefaultChannelPool.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index e4b2554762..c7d8f94919 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -24,11 +24,11 @@ import io.netty.util.Timeout; import io.netty.util.Timer; import io.netty.util.TimerTask; +import io.netty.util.internal.chmv8.ConcurrentHashMapV8; 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; @@ -39,9 +39,9 @@ public class DefaultChannelPool implements ChannelPool { private final static Logger log = LoggerFactory.getLogger(DefaultChannelPool.class); - private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); - private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); - private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); + private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); + private final ConcurrentHashMapV8 channel2IdleChannel = new ConcurrentHashMapV8(); + private final ConcurrentHashMapV8 channel2CreationDate = new ConcurrentHashMapV8(); private final AtomicBoolean closed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; From 8edfd54a93b61cf232d76efdbe2beffa3f58eb23 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 4 Jun 2014 17:47:04 -0700 Subject: [PATCH 0079/2070] [master] 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" --- .../providers/grizzly/Utils.java | 13 +--- .../bodyhandler/BodyGeneratorBodyHandler.java | 4 +- .../grizzly/bodyhandler/BodyHandler.java | 24 +++++-- .../bodyhandler/BodyHandlerFactory.java | 7 +- .../bodyhandler/ByteArrayBodyHandler.java | 19 +++-- .../grizzly/bodyhandler/ExpectHandler.java | 11 ++- .../grizzly/bodyhandler/FileBodyHandler.java | 23 ++++++- .../grizzly/bodyhandler/NoBodyHandler.java | 4 +- .../bodyhandler/ParamsBodyHandler.java | 4 +- .../grizzly/bodyhandler/PartsBodyHandler.java | 4 +- .../bodyhandler/StreamDataBodyHandler.java | 4 +- .../bodyhandler/StringBodyHandler.java | 4 +- .../filters/AsyncHttpClientFilter.java | 69 ++++++++++++------- 13 files changed, 126 insertions(+), 64 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java index 069652ef29..340b70527f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.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. @@ -13,12 +13,10 @@ package org.asynchttpclient.providers.grizzly; -import org.asynchttpclient.Request; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.attributes.AttributeStorage; -import org.glassfish.grizzly.http.Method; import java.net.URI; import java.util.concurrent.atomic.AtomicInteger; @@ -86,13 +84,4 @@ public static boolean isSpdyConnection(final Connection c) { Boolean result = SPDY.get(c); return result != null ? result : false; } - - public 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); - } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java index f4c018337c..53770d3b41 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyGeneratorBodyHandler.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. @@ -26,7 +26,7 @@ import java.io.IOException; -public final class BodyGeneratorBodyHandler implements BodyHandler { +public final class BodyGeneratorBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java index 44c907b9ba..2b6e17a32b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandler.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. @@ -19,11 +19,25 @@ import java.io.IOException; -public interface BodyHandler { +public abstract class BodyHandler { - static int MAX_CHUNK_SIZE = 8192; + public static int MAX_CHUNK_SIZE = 8192; - boolean handlesBodyType(final Request request); + public abstract 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(); + } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java index 44c7677e40..8b5cf4ff63 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/BodyHandlerFactory.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. @@ -27,7 +27,7 @@ public BodyHandlerFactory(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { new ParamsBodyHandler(grizzlyAsyncHttpProvider),// new StreamDataBodyHandler(),// new PartsBodyHandler(),// - new FileBodyHandler(),// + new FileBodyHandler(grizzlyAsyncHttpProvider),// new BodyGeneratorBodyHandler() // }; } @@ -39,7 +39,8 @@ public BodyHandler getBodyHandler(final Request request) { return h; } } - return new NoBodyHandler(); + + return null; } } // END BodyHandlerFactory diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java index 7731b92f26..2a16c06b60 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ByteArrayBodyHandler.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. @@ -24,11 +24,12 @@ import java.io.IOException; -public final class ByteArrayBodyHandler implements BodyHandler { +public final class ByteArrayBodyHandler extends BodyHandler { private final boolean compressionEnabled; - public ByteArrayBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { + public ByteArrayBodyHandler( + final GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { compressionEnabled = grizzlyAsyncHttpProvider.getClientConfig().isCompressionEnabled(); } @@ -39,7 +40,8 @@ public boolean handlesBodyType(final Request request) { } @SuppressWarnings({ "unchecked" }) - public boolean doHandle(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) throws IOException { + public boolean doHandle(final FilterChainContext ctx, final Request request, + final HttpRequestPacket requestPacket) throws IOException { final byte[] data = request.getByteData(); final MemoryManager mm = ctx.getMemoryManager(); @@ -54,4 +56,13 @@ public boolean doHandle(final FilterChainContext ctx, final Request request, fin 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 compressionEnabled ? -1 : request.getByteData().length; + } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java index cdb1553a03..f322aa80dc 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ExpectHandler.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. @@ -19,7 +19,7 @@ import java.io.IOException; -public final class ExpectHandler implements BodyHandler { +public final class ExpectHandler extends BodyHandler { private final BodyHandler delegate; private Request request; @@ -41,6 +41,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; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java index d957bf0ce6..70bed73210 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/FileBodyHandler.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. @@ -31,14 +31,22 @@ import java.io.FileInputStream; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; +import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; -public final class FileBodyHandler implements BodyHandler { +public final class FileBodyHandler extends BodyHandler { private static final boolean SEND_FILE_SUPPORT; static { SEND_FILE_SUPPORT = configSendFileSupport(); } + private final boolean compressionEnabled; + + public FileBodyHandler( + final GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { + compressionEnabled = grizzlyAsyncHttpProvider.getClientConfig().isCompressionEnabled(); + } + // ------------------------------------------------ Methods from BodyHandler public boolean handlesBodyType(final Request request) { @@ -51,7 +59,7 @@ public boolean doHandle(final FilterChainContext ctx, final Request request, fin final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); final HttpTxContext context = HttpTxContext.get(ctx); - if (!SEND_FILE_SUPPORT || requestPacket.isSecure()) { + if (compressionEnabled || !SEND_FILE_SUPPORT || requestPacket.isSecure()) { final FileInputStream fis = new FileInputStream(request.getFile()); final MemoryManager mm = ctx.getMemoryManager(); AtomicInteger written = new AtomicInteger(); @@ -98,6 +106,15 @@ public void completed(WriteResult result) { return true; } + @Override + protected long getContentLength(final Request request) { + if (request.getContentLength() >= 0) { + return request.getContentLength(); + } + + return compressionEnabled ? -1 : request.getFile().length(); + } + // --------------------------------------------------------- Private Methods private static void notifyHandlerIfNeeded(final HttpTxContext context, final HttpRequestPacket requestPacket, diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java index 879e894ea1..c3865952bf 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/NoBodyHandler.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. @@ -21,7 +21,7 @@ import java.io.IOException; -public final class NoBodyHandler implements BodyHandler { +public final class NoBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java index 8cf8992e5c..69c4a63236 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.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. @@ -31,7 +31,7 @@ import java.util.List; import java.util.Map; -public final class ParamsBodyHandler implements BodyHandler { +public final class ParamsBodyHandler extends BodyHandler { private final boolean compressionEnabled; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java index d7ffcd1683..11171d06a7 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.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. @@ -31,7 +31,7 @@ import java.io.IOException; import java.util.List; -public final class PartsBodyHandler implements BodyHandler { +public final class PartsBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java index 2647bd7c2a..79eb603242 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StreamDataBodyHandler.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. @@ -25,7 +25,7 @@ import java.io.IOException; import java.io.InputStream; -public final class StreamDataBodyHandler implements BodyHandler { +public final class StreamDataBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java index bf1e54855e..7785c1fc87 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/StringBodyHandler.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. @@ -25,7 +25,7 @@ import java.io.IOException; -public final class StringBodyHandler implements BodyHandler { +public final class StringBodyHandler extends BodyHandler { private final GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider; public StringBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 951a206951..90e57d95d1 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -73,7 +73,6 @@ import org.glassfish.grizzly.websockets.Version; import org.slf4j.Logger; -import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -198,7 +197,9 @@ private static void recycleRequestResponsePackets(final Connection c, final Http } } - private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, final FilterChainContext ctx) throws IOException { + private boolean sendAsGrizzlyRequest( + final RequestInfoHolder requestInfoHolder, + final FilterChainContext ctx) throws IOException { HttpTxContext httpTxContext = requestInfoHolder.getHttpTxContext(); if (httpTxContext == null) { @@ -230,18 +231,25 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, if (requestPacket == null) { requestPacket = new HttpRequestPacketImpl(); } - requestPacket.setMethod(request.getMethod()); + + final Method method = Method.valueOf(request.getMethod()); + + requestPacket.setMethod(method); requestPacket.setProtocol(Protocol.HTTP_1_1); // Special handling for CONNECT. - if (Method.CONNECT.matchesMethod(request.getMethod())) { + if (method == Method.CONNECT) { final int port = uri.getPort(); requestPacket.setRequestURI(uri.getHost() + ':' + (port == -1 ? 443 : port)); } else { requestPacket.setRequestURI(uri.getPath()); } - if (Utils.requestHasEntityBody(request)) { + final BodyHandler bodyHandler = isPayloadAllowed(method) ? + bodyHandlerFactory.getBodyHandler(request) : + null; + + if (bodyHandler != null) { final long contentLength = request.getContentLength(); if (contentLength >= 0) { requestPacket.setContentLengthLong(contentLength); @@ -301,35 +309,25 @@ private boolean sendAsGrizzlyRequest(final RequestInfoHolder requestInfoHolder, requestPacketLocal.getProcessingState().setHttpContext(httpCtx); requestPacketLocal.setConnection(c); - return sendRequest(sendingCtx, request, requestPacketLocal); + return sendRequest(sendingCtx, request, requestPacketLocal, + wrapWithExpectHandlerIfNeeded(bodyHandler, requestPacket)); } @SuppressWarnings("unchecked") - public boolean sendRequest(final FilterChainContext ctx, final Request request, final HttpRequestPacket requestPacket) + public boolean sendRequest(final FilterChainContext ctx, + final Request request, final HttpRequestPacket requestPacket, + final BodyHandler bodyHandler) throws IOException { boolean isWriteComplete = true; - if (Utils.requestHasEntityBody(request)) { + if (bodyHandler != null) { final HttpTxContext context = HttpTxContext.get(ctx); - BodyHandler handler = bodyHandlerFactory.getBodyHandler(request); - if (requestPacket.getHeaders().contains(Header.Expect) - && requestPacket.getHeaders().getValue(1).equalsIgnoreCase("100-Continue")) { - // We have to set the content-length now as the headers will be flushed - // before the FileBodyHandler is invoked. If we don't do it here, and - // the user didn't explicitly set the length, then the transfer-encoding - // will be chunked and zero-copy file transfer will not occur. - final File f = request.getFile(); - if (f != null) { - requestPacket.setContentLengthLong(f.length()); - } - handler = new ExpectHandler(handler); - } - context.setBodyHandler(handler); + context.setBodyHandler(bodyHandler); if (logger.isDebugEnabled()) { logger.debug("REQUEST: {}", requestPacket); } - isWriteComplete = handler.doHandle(ctx, request, requestPacket); + isWriteComplete = bodyHandler.doHandle(ctx, request, requestPacket); } else { HttpContent content = HttpContent.builder(requestPacket).last(true).build(); if (logger.isDebugEnabled()) { @@ -359,6 +357,31 @@ private static FilterChainContext checkAndHandleFilterChainUpdate(final FilterCh return ctxLocal; } + /** + * check if we need to wrap the BodyHandler with ExpectHandler + */ + private static 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 static boolean isPayloadAllowed(final Method method) { + return method.getPayloadExpectation() != Method.PayloadExpectation.NOT_ALLOWED; + } + private static void initTransferCompletionHandler(final Request request, final AsyncHandler h) throws IOException { if (h instanceof TransferCompletionHandler) { final FluentCaseInsensitiveStringsMap map = new FluentCaseInsensitiveStringsMap(request.getHeaders()); From 82cb11a779ae67f39c1f8359e192e56540bfc384 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 5 Jun 2014 17:38:32 +0200 Subject: [PATCH 0080/2070] Curse people setting public modifier on interface methods --- .../AsyncHttpClientRegistry.java | 1 + .../AsyncHttpProviderConfig.java | 8 +-- .../main/java/org/asynchttpclient/Body.java | 1 - .../org/asynchttpclient/BodyConsumer.java | 1 - .../asynchttpclient/ProgressAsyncHandler.java | 1 - .../java/org/asynchttpclient/Request.java | 57 ++++++++++--------- .../ResumableBodyConsumer.java | 1 - .../asynchttpclient/SignatureCalculator.java | 4 +- .../org/asynchttpclient/ThrowableHandler.java | 1 - .../org/asynchttpclient/UpgradeHandler.java | 1 - .../filter/IOExceptionFilter.java | 2 +- .../asynchttpclient/filter/RequestFilter.java | 2 +- .../filter/ResponseFilter.java | 2 +- .../listener/TransferListener.java | 13 +++-- .../resumable/ResumableAsyncHandler.java | 8 +-- .../resumable/ResumableListener.java | 9 ++- .../simple/SimpleAHCTransferListener.java | 2 +- .../spnego/SpnegoTokenGenerator.java | 1 - .../asynchttpclient/util/HostnameChecker.java | 4 +- .../asynchttpclient/websocket/WebSocket.java | 1 + .../websocket/WebSocketByteListener.java | 1 - .../websocket/WebSocketListener.java | 1 - .../websocket/WebSocketPingListener.java | 1 - .../websocket/WebSocketPongListener.java | 1 - .../websocket/WebSocketTextListener.java | 1 - .../asynchttpclient/extra/HttpProgress.java | 1 - .../request/body/FeedableBodyGenerator.java | 2 +- 27 files changed, 60 insertions(+), 68 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java index 740313380a..5e05afa780 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java @@ -79,3 +79,4 @@ public interface AsyncHttpClientRegistry { void clearAllInstances(); } + diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java index 8ba404b98b..f511580c9b 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpProviderConfig.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/Body.java b/api/src/main/java/org/asynchttpclient/Body.java index dacf0642d4..5a39306b2d 100644 --- a/api/src/main/java/org/asynchttpclient/Body.java +++ b/api/src/main/java/org/asynchttpclient/Body.java @@ -44,5 +44,4 @@ public interface Body extends Closeable { * @throws IOException */ void close() throws IOException; - } diff --git a/api/src/main/java/org/asynchttpclient/BodyConsumer.java b/api/src/main/java/org/asynchttpclient/BodyConsumer.java index ccebd5e8b0..0e93652bb1 100644 --- a/api/src/main/java/org/asynchttpclient/BodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/BodyConsumer.java @@ -36,5 +36,4 @@ public interface BodyConsumer extends Closeable { * @throws IOException */ void close() throws IOException; - } diff --git a/api/src/main/java/org/asynchttpclient/ProgressAsyncHandler.java b/api/src/main/java/org/asynchttpclient/ProgressAsyncHandler.java index a562addc42..bde0d5dd52 100644 --- a/api/src/main/java/org/asynchttpclient/ProgressAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/ProgressAsyncHandler.java @@ -44,5 +44,4 @@ public interface ProgressAsyncHandler extends AsyncHandler { * @return a {@link AsyncHandler.STATE} telling to CONTINUE or ABORT the current processing. */ STATE onContentWriteProgress(long amount, long current, long total); - } diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 2dd3864b98..248f6e5e5e 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -44,43 +44,43 @@ public interface Request { * * @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(); + URI getOriginalURI(); - public URI getURI(); + URI getURI(); - public URI getRawURI(); + 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 return true if request headers have been added, @@ -95,128 +95,129 @@ public interface Request { * * @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 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. * * @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 the request time out in milliseconds. * * @return requestTimeoutInMs. */ - public int getRequestTimeoutInMs(); + int getRequestTimeoutInMs(); /** * 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/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java b/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java index 3f327446c9..42e71536ce 100644 --- a/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/ResumableBodyConsumer.java @@ -33,5 +33,4 @@ public interface ResumableBodyConsumer extends BodyConsumer { * @throws IOException */ long getTransferredBytes() throws IOException; - } diff --git a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java index 6e0966437f..2f907b9390 100644 --- a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java @@ -35,5 +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/api/src/main/java/org/asynchttpclient/ThrowableHandler.java b/api/src/main/java/org/asynchttpclient/ThrowableHandler.java index cbafe59011..1bc28ea824 100644 --- a/api/src/main/java/org/asynchttpclient/ThrowableHandler.java +++ b/api/src/main/java/org/asynchttpclient/ThrowableHandler.java @@ -19,5 +19,4 @@ public interface ThrowableHandler { void onThrowable(Throwable t); - } diff --git a/api/src/main/java/org/asynchttpclient/UpgradeHandler.java b/api/src/main/java/org/asynchttpclient/UpgradeHandler.java index 9ed5e4a7b0..e541e67459 100644 --- a/api/src/main/java/org/asynchttpclient/UpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/UpgradeHandler.java @@ -33,5 +33,4 @@ public interface UpgradeHandler { * @param t a {@link Throwable} */ void onFailure(Throwable t); - } diff --git a/api/src/main/java/org/asynchttpclient/filter/IOExceptionFilter.java b/api/src/main/java/org/asynchttpclient/filter/IOExceptionFilter.java index 9473146273..99b3ee2ee0 100644 --- a/api/src/main/java/org/asynchttpclient/filter/IOExceptionFilter.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/filter/RequestFilter.java b/api/src/main/java/org/asynchttpclient/filter/RequestFilter.java index 520db598c5..9116ed0c1f 100644 --- a/api/src/main/java/org/asynchttpclient/filter/RequestFilter.java +++ b/api/src/main/java/org/asynchttpclient/filter/RequestFilter.java @@ -26,5 +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/api/src/main/java/org/asynchttpclient/filter/ResponseFilter.java b/api/src/main/java/org/asynchttpclient/filter/ResponseFilter.java index cdad3ce23c..a49a71f948 100644 --- a/api/src/main/java/org/asynchttpclient/filter/ResponseFilter.java +++ b/api/src/main/java/org/asynchttpclient/filter/ResponseFilter.java @@ -29,5 +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/api/src/main/java/org/asynchttpclient/listener/TransferListener.java b/api/src/main/java/org/asynchttpclient/listener/TransferListener.java index d61a675295..1043b3c561 100644 --- a/api/src/main/java/org/asynchttpclient/listener/TransferListener.java +++ b/api/src/main/java/org/asynchttpclient/listener/TransferListener.java @@ -24,19 +24,19 @@ 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 bytes a {@link byte[]} */ - public void onBytesReceived(byte[] bytes) throws IOException; + void onBytesReceived(byte[] bytes) throws IOException; /** * Invoked every time request's chunk are sent. @@ -45,17 +45,18 @@ public interface TransferListener { * @param current The amount of bytes transferred * @param total The total number of bytes transferred */ - public void onBytesSent(long amount, long current, long total); + void onBytesSent(long amount, long current, long total); /** * 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/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index 6b301b7f93..2463186d4c 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -254,14 +254,14 @@ public static interface ResumableProcessor { * @param key a key. The recommended way is to use an url. * @param transferredBytes The number of bytes successfully 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 discarded */ - public void remove(String key); + void remove(String key); /** * Save the current {@link Map} instance which contains information about the current transfer state. @@ -269,14 +269,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(); } diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableListener.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableListener.java index 252236cbae..c8af9c6561 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableListener.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java b/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java index b8e300f020..51448ee38e 100644 --- a/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/spnego/SpnegoTokenGenerator.java b/api/src/main/java/org/asynchttpclient/spnego/SpnegoTokenGenerator.java index ead1c19335..ee0b9876c4 100644 --- a/api/src/main/java/org/asynchttpclient/spnego/SpnegoTokenGenerator.java +++ b/api/src/main/java/org/asynchttpclient/spnego/SpnegoTokenGenerator.java @@ -51,5 +51,4 @@ public interface SpnegoTokenGenerator { byte[] generateSpnegoDERObject(byte[] kerberosTicket) throws IOException; - } diff --git a/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java b/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java index daf012deca..a25bb467e0 100644 --- a/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java +++ b/api/src/main/java/org/asynchttpclient/util/HostnameChecker.java @@ -21,7 +21,7 @@ */ public interface HostnameChecker { - public void match(String hostname, X509Certificate peerCertificate) throws CertificateException; + void match(String hostname, X509Certificate peerCertificate) throws CertificateException; - public boolean match(String hostname, Principal principal); + boolean match(String hostname, Principal principal); } diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocket.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocket.java index 9e9c981c16..81f7392b99 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocket.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocket.java @@ -108,3 +108,4 @@ public interface WebSocket extends Closeable { */ void close(); } + diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java index 55f35a3f2b..04dd4075ec 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java @@ -30,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/api/src/main/java/org/asynchttpclient/websocket/WebSocketListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketListener.java index bf187be07c..6c8b7fbc25 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketListener.java @@ -37,5 +37,4 @@ public interface WebSocketListener { * @param t a {@link Throwable} */ void onError(Throwable t); - } diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketPingListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketPingListener.java index 7abc8ab4a2..0567c90c2d 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketPingListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketPingListener.java @@ -22,5 +22,4 @@ public interface WebSocketPingListener extends WebSocketListener { * @param message a byte array */ void onPing(byte[] message); - } diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketPongListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketPongListener.java index f140a2208d..a27e93bfd4 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketPongListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketPongListener.java @@ -22,5 +22,4 @@ public interface WebSocketPongListener extends WebSocketListener { * @param message a byte array */ void onPong(byte[] message); - } diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java index d52bfad0ea..2ea133b1ec 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java +++ b/api/src/main/java/org/asynchttpclient/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/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java index 15af6debbc..19a3e22796 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java @@ -16,5 +16,4 @@ package org.asynchttpclient.extra; public interface HttpProgress { - } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java index 2e8da2d845..97bdc34701 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java @@ -47,7 +47,7 @@ public void feed(final ByteBuffer buffer, final boolean isLast) throws IOExcepti } public static interface FeedListener { - public void onContentAdded(); + void onContentAdded(); } public void setListener(FeedListener listener) { From d8a0355a5afef83dcc22a6afddfbc4b57e0d35ec Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 5 Jun 2014 17:45:37 +0200 Subject: [PATCH 0081/2070] minor clean up --- .../netty/channel/DefaultChannelPool.java | 89 ++++++++----------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index c7d8f94919..245723ff6e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -38,7 +38,7 @@ */ public class DefaultChannelPool implements ChannelPool { - private final static Logger log = LoggerFactory.getLogger(DefaultChannelPool.class); + private final static Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); private final ConcurrentHashMapV8 channel2IdleChannel = new ConcurrentHashMapV8(); private final ConcurrentHashMapV8 channel2CreationDate = new ConcurrentHashMapV8(); @@ -81,30 +81,24 @@ private void scheduleNewIdleChannelDetector(TimerTask task) { nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); } - private static class IdleChannel { - final String uri; + private static final class IdleChannel { + final String key; final Channel channel; final long start; - IdleChannel(String uri, Channel channel) { - this.uri = uri; + 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) { - 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 @@ -121,11 +115,11 @@ public void run(Timeout timeout) throws Exception { if (closed.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()); } } @@ -136,7 +130,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); @@ -151,28 +145,28 @@ public void run(Timeout timeout) throws Exception { 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, + 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.task()); @@ -183,46 +177,42 @@ public void run(Timeout timeout) throws Exception { * {@inheritDoc} */ public boolean offer(String uri, Channel channel) { - if (closed.get()) + if (closed.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); Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - ConcurrentLinkedQueue idleConnectionForHost = connectionsPool.get(uri); - if (idleConnectionForHost == null) { + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); + if (pooledConnectionForKey == null) { ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - idleConnectionForHost = connectionsPool.putIfAbsent(uri, newPool); - if (idleConnectionForHost == null) - idleConnectionForHost = newPool; + pooledConnectionForKey = connectionsPool.putIfAbsent(uri, newPool); + if (pooledConnectionForKey == null) + pooledConnectionForKey = newPool; } boolean added; - int size = idleConnectionForHost.size(); + int size = pooledConnectionForKey.size(); if (maxConnectionPerHost == -1 || size < maxConnectionPerHost) { IdleChannel idleChannel = new IdleChannel(uri, channel); - synchronized (idleConnectionForHost) { - added = idleConnectionForHost.add(idleChannel); + synchronized (pooledConnectionForKey) { + added = pooledConnectionForKey.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; @@ -237,13 +227,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.size() > 0) { - synchronized (idleConnectionForHost) { - idleChannel = idleConnectionForHost.poll(); + if (pooledConnectionForKey.size() > 0) { + synchronized (pooledConnectionForKey) { + idleChannel = pooledConnectionForKey.poll(); if (idleChannel != null) { channel2IdleChannel.remove(idleChannel.channel); } @@ -254,7 +244,7 @@ public Channel poll(String uri) { poolEmpty = true; } else if (!idleChannel.channel.isActive() || !idleChannel.channel.isOpen()) { idleChannel = null; - log.trace("Channel not connected or not opened!"); + LOGGER.trace("Channel not connected or not opened!"); } } } @@ -266,12 +256,11 @@ private boolean remove(IdleChannel pooledChannel) { return false; boolean isRemoved = false; - ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.uri); + ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.key); if (pooledConnectionForHost != null) { isRemoved = pooledConnectionForHost.remove(pooledChannel); } - isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; - return isRemoved; + return isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; } /** From 77be69e78ee6d6110bd6160aa5633b89d43dae98 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 11 Jun 2014 15:07:58 +0200 Subject: [PATCH 0082/2070] Release 1.8.10 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2c150d501..07afb045d3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.9 + 1.8.10 ``` From 4e4953c89b7b1d1c6394a99ac1fbf10431d20e26 Mon Sep 17 00:00:00 2001 From: sasurendran Date: Wed, 11 Jun 2014 17:42:20 -0700 Subject: [PATCH 0083/2070] Making changes so that asynchttpclient config default values are picked up from the asynchttpclient.properties in case they are not specified via system property. The search order for the default value for each config property is as such: 1. System Property 2. Property specified in asynchttpclient.properties 3. Default Value specified in code Also introducing JMockit for unit testing. --- .../AsyncHttpClientConfigDefaults.java | 59 ++++---- .../asynchttpclient/util/AsyncImplHelper.java | 2 +- .../org/asynchttpclient/util/MiscUtil.java | 50 ++++++- .../AsyncHttpClientConfigBuilderTest.java | 30 ++++ .../asynchttpclient/AsyncImplHelperMock.java | 23 +++ .../asynchttpclient/util/MiscUtilTest.java | 140 ++++++++++++++++++ pom.xml | 7 + 7 files changed, 281 insertions(+), 30 deletions(-) create mode 100644 api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java create mode 100644 api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java create mode 100644 api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index edd51169a1..8b40d67c45 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -12,13 +12,17 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.getBoolean; -import org.asynchttpclient.util.DefaultHostnameVerifier; import javax.net.ssl.HostnameVerifier; +import org.asynchttpclient.util.DefaultHostnameVerifier; +import static org.asynchttpclient.util.MiscUtil.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public final class AsyncHttpClientConfigDefaults { + public final static Logger logger = LoggerFactory.getLogger(AsyncHttpClientConfigDefaults.class); private AsyncHttpClientConfigDefaults() { } @@ -26,47 +30,47 @@ private AsyncHttpClientConfigDefaults() { public static final String ASYNC_CLIENT = AsyncHttpClientConfig.class.getName() + "."; public static int defaultMaxTotalConnections() { - return Integer.getInteger(ASYNC_CLIENT + "maxTotalConnections", -1); + return getIntValue(ASYNC_CLIENT + "maxTotalConnections", -1); } public static int defaultMaxConnectionPerHost() { - return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); + return getIntValue(ASYNC_CLIENT + "maxConnectionsPerHost", -1); } public static int defaultConnectionTimeOutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); + return getIntValue(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); } public static int defaultIdleConnectionInPoolTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); + return getIntValue(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); } public static int defaultIdleConnectionTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); + return getIntValue(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); } public static int defaultRequestTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); + return getIntValue(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); } public static int defaultWebSocketIdleTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); + return getIntValue(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); } public static int defaultMaxConnectionLifeTimeInMs() { - return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); + return getIntValue(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); } public static boolean defaultRedirectEnabled() { - return Boolean.getBoolean(ASYNC_CLIENT + "redirectsEnabled"); + return getBooleanValue(ASYNC_CLIENT + "redirectsEnabled",false); } public static int defaultMaxRedirects() { - return Integer.getInteger(ASYNC_CLIENT + "maxRedirects", 5); + return getIntValue(ASYNC_CLIENT + "maxRedirects", 5); } public static boolean defaultCompressionEnabled() { - return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); + return getBooleanValue(ASYNC_CLIENT + "compressionEnabled",false); } public static String defaultUserAgent() { @@ -74,48 +78,48 @@ public static String defaultUserAgent() { } public static int defaultIoThreadMultiplier() { - return Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2); + return getIntValue(ASYNC_CLIENT + "ioThreadMultiplier", 2); } public static boolean defaultUseProxySelector() { - return Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); + return getBooleanValue(ASYNC_CLIENT + "useProxySelector",false); } public static boolean defaultUseProxyProperties() { - return Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); + return getBooleanValue(ASYNC_CLIENT + "useProxyProperties",false); } public static boolean defaultStrict302Handling() { - return Boolean.getBoolean(ASYNC_CLIENT + "strict302Handling"); + return getBooleanValue(ASYNC_CLIENT + "strict302Handling",false); } public static boolean defaultAllowPoolingConnection() { - return getBoolean(ASYNC_CLIENT + "allowPoolingConnection", true); + return getBooleanValue(ASYNC_CLIENT + "allowPoolingConnection", true); } public static boolean defaultUseRelativeURIsWithSSLProxies() { - return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + return getBooleanValue(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); + return getIntValue(ASYNC_CLIENT + "requestCompressionLevel", -1); } public static int defaultMaxRequestRetry() { - return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); + return getIntValue(ASYNC_CLIENT + "maxRequestRetry", 5); } public static boolean defaultAllowSslConnectionPool() { - return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); + return getBooleanValue(ASYNC_CLIENT + "allowSslConnectionPool", true); } public static boolean defaultUseRawUrl() { - return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrl"); + return getBooleanValue(ASYNC_CLIENT + "useRawUrl",false); } public static boolean defaultRemoveQueryParamOnRedirect() { - return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); + return getBooleanValue(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); } public static HostnameVerifier defaultHostnameVerifier() { @@ -123,14 +127,15 @@ public static HostnameVerifier defaultHostnameVerifier() { } public static boolean defaultSpdyEnabled() { - return Boolean.getBoolean(ASYNC_CLIENT + "spdyEnabled"); + return getBooleanValue(ASYNC_CLIENT + "spdyEnabled",false); } public static int defaultSpdyInitialWindowSize() { - return Integer.getInteger(ASYNC_CLIENT + "spdyInitialWindowSize", 10 * 1024 * 1024); + return getIntValue(ASYNC_CLIENT + "spdyInitialWindowSize", 10 * 1024 * 1024); } public static int defaultSpdyMaxConcurrentStreams() { - return Integer.getInteger(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); + return getIntValue(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); } + } diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java index a61d2d74d6..47b23bf767 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java @@ -59,7 +59,7 @@ public static Class getAsyncImplClass(String propertyName) { return asyncHttpClientImplClass; } - private static Properties getAsyncImplProperties() { + public static Properties getAsyncImplProperties() { try { return AccessController.doPrivileged(new PrivilegedExceptionAction() { public Properties run() throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 7a80e00268..65c8db0b11 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -14,6 +14,9 @@ import java.util.Collection; import java.util.Map; +import java.util.Properties; + +import org.asynchttpclient.AsyncHttpClientConfigDefaults; public class MiscUtil { @@ -40,8 +43,51 @@ public static boolean isNonEmpty(Map map) { return map != null && !map.isEmpty(); } - public static boolean getBoolean(String systemPropName, boolean defaultValue) { + /* public static boolean getBoolean(String systemPropName, boolean defaultValue) { String systemPropValue = System.getProperty(systemPropName); return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; - } + }*/ + + public static Integer getIntValue(String property,int defaultValue){ + //Read system property and if not null return that. + Integer value = Integer.getInteger(property); + if(value != null) + return value; + Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); + if(asyncHttpClientConfigProperties!=null){ + String valueString=asyncHttpClientConfigProperties.getProperty(property); + try{ + //If property is present and is non null parse it. + if(valueString != null) + return Integer.parseInt(valueString); + }catch(NumberFormatException e){ + //If property couldn't be parsed log the error message and return default value. + AsyncHttpClientConfigDefaults.logger.error("Property : " + property + " has value = " + valueString + + " which couldn't be parsed to an int value. Returning default value: " + defaultValue,e); + } + } + return defaultValue; + } + + public static Boolean getBooleanValue(String property,boolean defaultValue){ + String value = System.getProperty(property); + Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); + //If system property is invalid and property file is present then read value + //from property file + if(!MiscUtil.isValidBooleanValue(value) && asyncHttpClientConfigProperties!=null) + value=asyncHttpClientConfigProperties.getProperty(property); + //If valid value has been found return that value + if(MiscUtil.isValidBooleanValue(value)) + return Boolean.parseBoolean(value); + //If a value has been specified but can't be parsed into a boolean log a message + //stating that value is unparseable and default values are being used. + if(value != null) + AsyncHttpClientConfigDefaults.logger.error("Property : " + property + " has value = " + value + + " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); + return defaultValue; + } + + private static boolean isValidBooleanValue(String value){ + return value != null && ("true".equalsIgnoreCase(value)||"false".equalsIgnoreCase(value)); + } } diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java b/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java new file mode 100644 index 0000000000..02d532f3d4 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java @@ -0,0 +1,30 @@ +package org.asynchttpclient; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class AsyncHttpClientConfigBuilderTest { + + @Test + public void testDefaultConfigValues(){ + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); + Assert.assertEquals(config.getConnectionTimeoutInMs(),60000); + Assert.assertEquals(config.getRequestTimeoutInMs(),60000); + Assert.assertEquals(config.getIdleConnectionTimeoutInMs(),60000); + Assert.assertFalse(config.isCompressionEnabled()); + Assert.assertFalse(config.isRedirectEnabled()); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"connectionTimeoutInMs","1000"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"requestTimeoutInMs","500"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"compressionEnabled","true"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"redirectsEnabled","true"); + config = new AsyncHttpClientConfig.Builder().build(); + Assert.assertEquals(config.getConnectionTimeoutInMs(),1000); + Assert.assertEquals(config.getRequestTimeoutInMs(), 500); + Assert.assertTrue(config.isCompressionEnabled()); + Assert.assertTrue(config.isRedirectEnabled()); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"connectionTimeoutInMs"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"requestTimeoutInMs"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"compressionEnabled"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"defaultRedirectsEnabled"); + } +} diff --git a/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java b/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java new file mode 100644 index 0000000000..562af7a3dd --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java @@ -0,0 +1,23 @@ +package org.asynchttpclient; + +import java.util.Properties; + +import mockit.Mock; +import mockit.MockUp; + +import org.asynchttpclient.util.AsyncImplHelper; + +public class AsyncImplHelperMock extends MockUp { + + private static Properties properties; + + public AsyncImplHelperMock(Properties properties){ + this.properties=properties; + } + + @Mock + public Properties getAsyncImplProperties() { + return properties; + } + +} diff --git a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java new file mode 100644 index 0000000000..d9f4bbed19 --- /dev/null +++ b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java @@ -0,0 +1,140 @@ +package org.asynchttpclient.util; + +import java.util.Properties; + +import mockit.Deencapsulation; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncImplHelperMock; +import org.asynchttpclient.AsyncHttpClientConfig.Builder; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class MiscUtilTest { + private final Integer MY_SPECIAL_INT_VALUE = 10; + private final Integer MY_SPECIAL_SYSTEM_INT_VALUE = 100; + private final String MY_SPECIAL_INT_PROPERTY = "my.special.int.property"; + private final String MY_SPECIAL_BOOLEAN_PROPERTY = "my.special.boolean.property"; + private final Integer MY_SPECIAL_INT_DEFAULT_VALUE = -100; + + + @Test + public void testGetIntegerValue() { + // Setup a AsyncImplHelperMock that returns a mock + // asynchttpclient.properties with a value + // set for 'my.special.int.property' property + Properties properties = new Properties(); + properties.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_VALUE.toString()); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + + + // Assert that the getIntValue() method returns 10 + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); + // Set a system property that overrides the value in the + // asynchttpclient.properties + System.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_SYSTEM_INT_VALUE.toString()); + // Assert 100 is returned, i.e. system property takes precedence over + // property in asynchttpclient.properties + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1),MY_SPECIAL_SYSTEM_INT_VALUE); + // Clear the system property + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + // Assert that the value set in asynchttpclient.properties is returned + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); + // Assert that the value set in asynchttpclient.properties is returned + // even though corrupt system property is set. + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + } + + @Test + public void testGetBooleanValue() { + // Setup a AsyncImplHelperMock that returns a mock + // asynchttpclient.properties with a value + // set for 'my.special.int.property' property + Properties properties = new Properties(); + properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "true"); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + + + // Assert that the getBooleanValue() method returns TRUE + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + // Set a system property that overrides the value in the + // asynchttpclient.properties + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "false"); + // Assert false is returned, i.e. system property takes precedence over + // property in asynchttpclient.properties + Assert.assertFalse(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Clear the system property + System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); + // Assert that the value set in asynchttpclient.properties is returned + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that the value set in asynchttpclient.properties is returned + // even though corrupt system property is set. + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); + } + + @Test + public void testGetDefaultIntegerValue() { + + // Assert that the getIntValue() method returns the default value if + // Properties is not present + Assert.assertEquals( + MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), + MY_SPECIAL_INT_DEFAULT_VALUE); + // Setup up a mock of a asynchttpclient.properties that initially is empty + Properties properties = new Properties(); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + + + // Assert that the getIntValue() method returns the default value if there is no + // property set in the asynchttpclient.properties + Assert.assertEquals( + MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), + MY_SPECIAL_INT_DEFAULT_VALUE); + //Now set a corrupt value in the asynchttpclient.properties + properties.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); + // Assert that the getIntValue() method returns the default value if there is a corrupt + // property set in the asynchttpclient.properties + Assert.assertEquals( + MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), + MY_SPECIAL_INT_DEFAULT_VALUE); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); + // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is returned + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), + MY_SPECIAL_INT_DEFAULT_VALUE); + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + } + + + + @Test + public void testGetDefaultBooleanValue() { + // Assert that the getBooleanValue() method returns the default value if + // asynchttpclient.properties is not present + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Setup up a mock of a asynchttpclient.properties that initially is empty + Properties properties = new Properties(); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + + + // Assert that the getBooleanValue() method returns the default value if there is no + // property set in the asynchttpclient.properties + Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + //Now set a corrupt value in the asynchttpclient.properties + properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that the getBooleanValue() method returns the default value if there is a corrupt + // property set in the asynchttpclient.properties + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is returned + Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + } +} diff --git a/pom.xml b/pom.xml index a4e54d8ded..47d662b815 100644 --- a/pom.xml +++ b/pom.xml @@ -519,6 +519,12 @@ ${privilegedaccessor.version} test + + com.googlecode.jmockit + jmockit + ${jmockit.version} + test + http://oss.sonatype.org/content/repositories/snapshots @@ -533,6 +539,7 @@ 6.0.29 2.4 1.3 + 1.5 1.2.2 From 8b736ced1acb84da364b89adeeb867584bebc722 Mon Sep 17 00:00:00 2001 From: sasurendran Date: Wed, 11 Jun 2014 17:42:20 -0700 Subject: [PATCH 0084/2070] Making changes so that asynchttpclient config default values are picked up from the asynchttpclient.properties in case they are not specified via system property. The search order for the default value for each config property is as such: 1. System Property 2. Property specified in asynchttpclient.properties 3. Default Value specified in code Also introducing JMockit for unit testing. --- .../asynchttpclient/AsyncHttpClientConfigDefaults.java | 5 ++++- .../main/java/org/asynchttpclient/util/MiscUtil.java | 10 +++++++--- .../java/org/asynchttpclient/util/MiscUtilTest.java | 10 ++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 8b40d67c45..16818d1aa9 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -14,6 +14,9 @@ +import static org.asynchttpclient.util.MiscUtil.getBooleanValue; +import static org.asynchttpclient.util.MiscUtil.getIntValue; +import org.asynchttpclient.util.DefaultHostnameVerifier; import javax.net.ssl.HostnameVerifier; import org.asynchttpclient.util.DefaultHostnameVerifier; @@ -22,7 +25,7 @@ import org.slf4j.LoggerFactory; public final class AsyncHttpClientConfigDefaults { - public final static Logger logger = LoggerFactory.getLogger(AsyncHttpClientConfigDefaults.class); + private AsyncHttpClientConfigDefaults() { } diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 65c8db0b11..486140035b 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -12,13 +12,17 @@ */ package org.asynchttpclient.util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Map; import java.util.Properties; -import org.asynchttpclient.AsyncHttpClientConfigDefaults; + public class MiscUtil { + + public final static Logger logger = LoggerFactory.getLogger(MiscUtil.class); private MiscUtil() { } @@ -62,7 +66,7 @@ public static Integer getIntValue(String property,int defaultValue){ return Integer.parseInt(valueString); }catch(NumberFormatException e){ //If property couldn't be parsed log the error message and return default value. - AsyncHttpClientConfigDefaults.logger.error("Property : " + property + " has value = " + valueString + + logger.error("Property : " + property + " has value = " + valueString + " which couldn't be parsed to an int value. Returning default value: " + defaultValue,e); } } @@ -82,7 +86,7 @@ public static Boolean getBooleanValue(String property,boolean defaultValue){ //If a value has been specified but can't be parsed into a boolean log a message //stating that value is unparseable and default values are being used. if(value != null) - AsyncHttpClientConfigDefaults.logger.error("Property : " + property + " has value = " + value + + logger.error("Property : " + property + " has value = " + value + " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); return defaultValue; } diff --git a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java index d9f4bbed19..52b698b40e 100644 --- a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java +++ b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java @@ -2,11 +2,7 @@ import java.util.Properties; -import mockit.Deencapsulation; - -import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncImplHelperMock; -import org.asynchttpclient.AsyncHttpClientConfig.Builder; import org.testng.Assert; import org.testng.annotations.Test; @@ -105,7 +101,8 @@ public void testGetDefaultIntegerValue() { MY_SPECIAL_INT_DEFAULT_VALUE); // Set a corrupt system property System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is returned + // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is + //returned Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); System.clearProperty(MY_SPECIAL_INT_PROPERTY); @@ -133,7 +130,8 @@ public void testGetDefaultBooleanValue() { Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); // Set a corrupt system property System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is returned + // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is + //returned Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); System.clearProperty(MY_SPECIAL_INT_PROPERTY); } From df81d4420432c814c57a1d7acb4b503c5a3a6b1d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 10:23:58 +0200 Subject: [PATCH 0085/2070] Make NPE message more explicit when passing a null hostname to avoid proxy, close #560, close #561 --- .../main/java/org/asynchttpclient/util/ProxyUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index b48f7c7535..a2ce5413d8 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/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 0ef53c580c5e058c451176667a6ac52b18c1543d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 11:11:21 +0200 Subject: [PATCH 0086/2070] RequestBuilder.setUrl shouldn't accept an URI without a host, close #571 --- .../main/java/org/asynchttpclient/RequestBuilderBase.java | 5 ++++- .../org/asynchttpclient/async/AsyncProvidersBasicTest.java | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 3b8fbfe04c..8fbf20fb29 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -388,8 +388,11 @@ 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/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 00a1653678..379027d662 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -386,15 +386,12 @@ public void onThrowable(Throwable t) { } } - @Test(groups = { "online", "default_provider", "async" }) + @Test(groups = { "online", "default_provider", "async" }, expectedExceptions = { NullPointerException.class }) public void asyncNullSchemeTest() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { client.prepareGet("www.sun.com").execute(); - fail(); - } catch (IllegalArgumentException ex) { - assertTrue(true); } finally { client.close(); } @@ -1555,7 +1552,7 @@ public void getShouldAllowBody() throws IllegalArgumentException, IOException { } } - @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 02f069d5a3873d81ab9211247aeee7a4b4ffce7d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 12:13:05 +0200 Subject: [PATCH 0087/2070] minor clean up, properly use NPE instead of IAE --- .../java/org/asynchttpclient/RequestBuilder.java | 15 +++++++-------- .../org/asynchttpclient/RequestBuilderBase.java | 10 +++++----- .../asynchttpclient/SimpleAsyncHttpClient.java | 16 ++++++++-------- .../multipart/MultipartUtils.java | 7 +++---- .../asynchttpclient/multipart/StringPart.java | 2 +- .../java/org/asynchttpclient/util/DateUtil.java | 8 ++++---- .../async/AsyncProvidersBasicTest.java | 2 +- .../providers/grizzly/FeedableBodyGenerator.java | 2 +- .../netty/request/body/BodyChunkedInput.java | 5 ++--- .../netty/request/body/BodyFileRegion.java | 5 ++--- 10 files changed, 34 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilder.java b/api/src/main/java/org/asynchttpclient/RequestBuilder.java index 5718b37530..57f888ff95 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilder.java +++ b/api/src/main/java/org/asynchttpclient/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,7 +85,7 @@ public Request build() { } @Override - public RequestBuilder setBody(byte[] data) throws IllegalArgumentException { + public RequestBuilder setBody(byte[] data) { return super.setBody(data); } @@ -93,15 +93,14 @@ public RequestBuilder setBody(byte[] data) throws IllegalArgumentException { * Set a Stream for chunking * @param stream - An {@link InputStream} * @return a {@link RequestBuilder} - * @throws IllegalArgumentException */ @Override - 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); } @@ -121,12 +120,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/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 8fbf20fb29..01f0eaea05 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -514,7 +514,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(); @@ -522,7 +522,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(); @@ -530,7 +530,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(); @@ -560,7 +560,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) { @@ -570,7 +570,7 @@ 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); diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 3bbf84d7fb..4147e3e8d0 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -373,9 +373,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); @@ -385,13 +385,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); @@ -428,7 +428,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; } @@ -443,7 +443,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; } @@ -468,12 +468,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/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index e73cb802a6..9abc5b67d6 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java @@ -61,7 +61,7 @@ private MultipartUtils() { */ public static MultipartBody newMultipartBody(List parts, FluentCaseInsensitiveStringsMap requestHeaders) { if (parts == null) { - throw new IllegalArgumentException("parts cannot be null"); + throw new NullPointerException("parts"); } byte[] multipartBoundary; @@ -162,9 +162,8 @@ public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) public static byte[] getMessageEnd(byte[] partBoundary) throws IOException { - if (partBoundary == null || partBoundary.length == 0) { + if (!isNonEmpty(partBoundary)) throw new IllegalArgumentException("partBoundary may not be empty"); - } ByteArrayOutputStream out = new ByteArrayOutputStream(); OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); @@ -180,7 +179,7 @@ public static long getLengthOfParts(List parts, byte[] partBoundary) { try { if (parts == null) { - throw new IllegalArgumentException("Parts may not be null"); + throw new NullPointerException("parts"); } long total = 0; for (Part part : parts) { diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index b8061a3088..a6d60b7153 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -60,7 +60,7 @@ 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"); + throw new NullPointerException("value"); } if (value.indexOf(0) != -1) { // See RFC 2048, 2.8. "8bit Data" diff --git a/api/src/main/java/org/asynchttpclient/util/DateUtil.java b/api/src/main/java/org/asynchttpclient/util/DateUtil.java index 549174f755..a41ec9deba 100644 --- a/api/src/main/java/org/asynchttpclient/util/DateUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/DateUtil.java @@ -131,7 +131,7 @@ public static Date parseDate(String dateValue, Collection dateFormats) t public static Date parseDate(String dateValue, Collection dateFormats, Date startDate) throws DateParseException { if (dateValue == null) { - throw new IllegalArgumentException("dateValue is null"); + throw new NullPointerException("dateValue"); } if (dateFormats == null) { dateFormats = DEFAULT_PATTERNS; @@ -187,14 +187,14 @@ public static String formatDate(Date date) { * @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. + * @throws NullPointerException If the given date pattern is invalid. * @see java.text.SimpleDateFormat */ public static String formatDate(Date date, String pattern) { if (date == null) - throw new IllegalArgumentException("date is null"); + throw new NullPointerException("date"); if (pattern == null) - throw new IllegalArgumentException("pattern is null"); + throw new NullPointerException("pattern"); SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US); formatter.setTimeZone(GMT); diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 379027d662..accbe651a7 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -1543,7 +1543,7 @@ public void onThrowable(Throwable t) { } @Test(groups = { "standalone", "default_provider" }) - public void getShouldAllowBody() throws IllegalArgumentException, IOException { + public void getShouldAllowBody() throws IOException { AsyncHttpClient client = getAsyncHttpClient(null); try { client.prepareGet(getTargetUrl()).setBody("Boo!").execute(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java index 1717dcba18..6514edb61a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/FeedableBodyGenerator.java @@ -309,7 +309,7 @@ protected BaseFeeder(FeedableBodyGenerator feedableBodyGenerator) { @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."); + throw new NullPointerException("buffer"); } if (!feedableBodyGenerator.asyncTransferInitiated) { throw new IllegalStateException("Asynchronous transfer has not been initiated."); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java index 5fbe753846..271046a3e7 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java @@ -35,9 +35,8 @@ public 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 7d005c6c0d..857b610784 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -29,9 +29,8 @@ public class BodyFileRegion extends AbstractReferenceCounted implements FileRegi private long transfered; public BodyFileRegion(RandomAccessBody body) { - if (body == null) { - throw new IllegalArgumentException("no body specified"); - } + if (body == null) + throw new NullPointerException("body"); this.body = body; } From 01e61a10ed1bdd4839f4752c287192cfb20b59c6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 13:23:38 +0200 Subject: [PATCH 0088/2070] Minor ProxyUtils.matchNonProxyHost clean up, still very incomplete --- .../org/asynchttpclient/util/ProxyUtils.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index a2ce5413d8..1b183dd3e8 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/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 @@ -116,22 +125,12 @@ 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 (isNonEmpty(nonProxyHosts)) { for (String nonProxyHost : nonProxyHosts) { - // FIXME use regionMatches instead - 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(hostname, nonProxyHost)) return true; - } else if (nonProxyHost.equalsIgnoreCase(targetHost)) { - return true; - } } } From eb84fa587bdcf31ba79a15887813972abea5e674 Mon Sep 17 00:00:00 2001 From: Will Sargent Date: Wed, 2 Apr 2014 22:13:44 -0700 Subject: [PATCH 0089/2070] Ensure certificate verification by using a singleton. --- .../org/asynchttpclient/util/SslUtils.java | 134 ++---------------- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/netty/channel/Channels.java | 2 +- 3 files changed, 12 insertions(+), 126 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index 29c7b70011..10920fdb47 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -15,30 +15,25 @@ */ package org.asynchttpclient.util; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; 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; + private static class SingletonHolder { + public static final SslUtils instance = new SslUtils(); + } + + public static SslUtils getInstance() { + return SingletonHolder.instance; + } - public static SSLEngine getSSLEngine() throws GeneralSecurityException, IOException { + public SSLEngine getSSLEngine() throws GeneralSecurityException, IOException { SSLEngine engine = null; SSLContext context = getSSLContext(); @@ -50,117 +45,8 @@ public static SSLEngine getSSLEngine() throws GeneralSecurityException, IOExcept return engine; } - 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; - } - - 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(); - } - - 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; - } - - static SSLContext getLooseSSLContext() throws GeneralSecurityException { - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { LooseTrustManager.INSTANCE }, new SecureRandom()); - return sslContext; - } - - static class LooseTrustManager implements X509TrustManager { - - public static final LooseTrustManager INSTANCE = new LooseTrustManager(); - - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return new java.security.cert.X509Certificate[0]; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { - } - } - - 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"; - - 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"; - } - } + public SSLContext getSSLContext() throws GeneralSecurityException, IOException { + return SSLContext.getDefault(); } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 6949ca9be3..0290789067 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -253,7 +253,7 @@ public void onTimeout(Connection connection) { SSLContext context = clientConfig.getSSLContext(); if (context == null) { try { - context = SslUtils.getSSLContext(); + context = SslUtils.getInstance().getSSLContext(); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 64bdf7ea81..8900449865 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -204,7 +204,7 @@ private Timer newNettyTimer() { private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException { SSLEngine sslEngine = config.getSSLEngineFactory().newSSLEngine(); if (sslEngine == null) { - sslEngine = SslUtils.getSSLEngine(); + sslEngine = SslUtils.getInstance().getSSLEngine(); } return sslEngine; } From e5e6489941e222d4b510ba09ce7b53e9eed02601 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 18:42:56 +0200 Subject: [PATCH 0090/2070] Move setting a SSLEngineFactory into Netty specific conf as Grizzly doesn't use it --- .../AsyncHttpClientConfig.java | 26 ------------------- .../AsyncHttpClientConfigBean.java | 5 ---- .../org/asynchttpclient/util/SslUtils.java | 14 ---------- .../netty/NettyAsyncHttpProviderConfig.java | 11 ++++++++ .../providers/netty/channel/Channels.java | 18 ++++++++++--- 5 files changed, 25 insertions(+), 49 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index babb8cbd9e..e450c60a6e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -25,7 +25,6 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import java.io.IOException; import java.io.InputStream; @@ -94,7 +93,6 @@ public class AsyncHttpClientConfig { protected ExecutorService applicationThreadPool; protected ProxyServerSelector proxyServerSelector; protected SSLContext sslContext; - protected SSLEngineFactory sslEngineFactory; protected AsyncHttpProviderConfig providerConfig; protected Realm realm; protected List requestFilters; @@ -169,7 +167,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.userAgent = userAgent; this.allowPoolingConnection = keepAlive; this.sslContext = sslContext; - this.sslEngineFactory = sslEngineFactory; this.providerConfig = providerConfig; this.realm = realm; this.requestFilters = requestFilters; @@ -332,28 +329,6 @@ public SSLContext getSSLContext() { return sslContext; } - /** - * 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 AsyncHttpProviderConfig} * @@ -1122,7 +1097,6 @@ public Builder(AsyncHttpClientConfig prototype) { realm = prototype.getRealm(); requestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); - sslEngineFactory = prototype.getSSLEngineFactory(); userAgent = prototype.getUserAgent(); redirectEnabled = prototype.isRedirectEnabled(); compressionEnabled = prototype.isCompressionEnabled(); diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 98ab988ebb..d48b477eb3 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -175,11 +175,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; diff --git a/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index 10920fdb47..14c2629c61 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -16,7 +16,6 @@ package org.asynchttpclient.util; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import java.io.IOException; import java.security.GeneralSecurityException; @@ -33,20 +32,7 @@ public static SslUtils getInstance() { return SingletonHolder.instance; } - public SSLEngine getSSLEngine() throws GeneralSecurityException, IOException { - SSLEngine engine = null; - - SSLContext context = getSSLContext(); - if (context != null) { - engine = context.createSSLEngine(); - engine.setUseClientMode(true); - } - - return engine; - } - public SSLContext getSSLContext() throws GeneralSecurityException, IOException { return SSLContext.getDefault(); } - } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index f4a0022bad..ac75499993 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -17,6 +17,7 @@ package org.asynchttpclient.providers.netty; import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.SSLEngineFactory; import org.asynchttpclient.providers.netty.channel.ChannelPool; import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; @@ -93,6 +94,8 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig Date: Thu, 12 Jun 2014 21:47:02 +0200 Subject: [PATCH 0091/2070] Introduce acceptAnyCertificate config, defaulting to false, close #526, close #352 --- .../AsyncHttpClientConfig.java | 18 ++++++++- .../AsyncHttpClientConfigBean.java | 6 +++ .../AsyncHttpClientConfigDefaults.java | 4 ++ .../SimpleAsyncHttpClient.java | 5 +++ .../org/asynchttpclient/util/MiscUtil.java | 4 ++ .../org/asynchttpclient/util/SslUtils.java | 37 ++++++++++++++++++- .../async/HttpToHttpsRedirectTest.java | 18 +++++++-- .../async/ProxyTunnellingTest.java | 16 ++++++-- .../websocket/ProxyTunnellingTest.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../GrizzlyFeedableBodyGeneratorTest.java | 2 + .../providers/netty/channel/Channels.java | 7 ++-- 12 files changed, 104 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index e450c60a6e..444ceda349 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -112,6 +112,7 @@ public class AsyncHttpClientConfig { protected int spdyInitialWindowSize; protected int spdyMaxConcurrentStreams; protected TimeConverter timeConverter; + protected boolean acceptAnyCertificate; protected AsyncHttpClientConfig() { } @@ -151,7 +152,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, // boolean spdyEnabled, // int spdyInitialWindowSize, // int spdyMaxConcurrentStreams, // - TimeConverter timeConverter) { + TimeConverter timeConverter, // + boolean acceptAnyCertificate) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -187,6 +189,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; this.timeConverter = timeConverter; + this.acceptAnyCertificate = acceptAnyCertificate; } @@ -533,6 +536,10 @@ public TimeConverter getTimeConverter() { return timeConverter; } + public boolean isAcceptAnyCertificate() { + return acceptAnyCertificate; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -564,6 +571,7 @@ public static class Builder { private boolean spdyEnabled = defaultSpdyEnabled(); private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private ScheduledExecutorService reaper; private ExecutorService applicationThreadPool; @@ -1078,6 +1086,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. * @@ -1186,7 +1199,8 @@ public Thread newThread(Runnable r) { spdyEnabled, // spdyInitialWindowSize, // spdyMaxConcurrentStreams, // - timeConverter); + timeConverter, // + acceptAnyCertificate); } } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index d48b477eb3..463d0c2c37 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -70,6 +70,7 @@ void configureDefaults() { spdyEnabled = defaultSpdyEnabled(); spdyInitialWindowSize = defaultSpdyInitialWindowSize(); spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } else if (defaultUseProxyProperties()) { @@ -234,4 +235,9 @@ public AsyncHttpClientConfigBean setIoThreadMultiplier(int ioThreadMultiplier) { this.ioThreadMultiplier = ioThreadMultiplier; return this; } + + public AsyncHttpClientConfigBean setAcceptAnyCertificate(boolean acceptAnyCertificate) { + this.acceptAnyCertificate = acceptAnyCertificate; + return this; + } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index edd51169a1..3cb9ebddc7 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -133,4 +133,8 @@ public static int defaultSpdyInitialWindowSize() { public static int defaultSpdyMaxConcurrentStreams() { return Integer.getInteger(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); } + + public static boolean defaultAcceptAnyCertificate() { + return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false); + } } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 4147e3e8d0..b96d69a91f 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -678,6 +678,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/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 7a80e00268..3cad6cfd37 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.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/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index 14c2629c61..becb9ed943 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -16,14 +16,47 @@ package org.asynchttpclient.util; import javax.net.ssl.SSLContext; +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; /** * 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 { + + static class LooseTrustManager implements X509TrustManager { + + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[0]; + } + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + } + + 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); + } catch (KeyManagementException e) { + throw new ExceptionInInitializerError(e); + } + } + private static class SingletonHolder { public static final SslUtils instance = new SslUtils(); } @@ -32,7 +65,7 @@ public static SslUtils getInstance() { return SingletonHolder.instance; } - public SSLContext getSSLContext() throws GeneralSecurityException, IOException { - return SSLContext.getDefault(); + public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { + return acceptAnyCertificate? looseTrustManagerSSLContext: SSLContext.getDefault(); } } diff --git a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java index f754ac83a5..132c87f453 100644 --- a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java @@ -96,7 +96,11 @@ public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { public void httpToHttpsRedirect() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); @@ -112,7 +116,11 @@ public void httpToHttpsRedirect() throws Exception { public void httpToHttpsProperConfig() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); @@ -134,7 +142,11 @@ public void httpToHttpsProperConfig() throws Exception { public void relativeLocationUrl() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); diff --git a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java index 4f223f40ce..01d85ac608 100644 --- a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java @@ -74,12 +74,14 @@ public void tearDownGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void testRequestProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { - AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirects(true); ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - AsyncHttpClientConfig config = b.build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); + AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); @@ -108,6 +110,7 @@ public void testConfigProxy() throws IOException, InterruptedException, Executio AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// .setFollowRedirects(true)// .setProxyServer(new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1))// + .setAcceptAnyCertificate(true)// .build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { @@ -136,7 +139,12 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()// .setProviderClass(getProviderClass())// - .setProxyProtocol(ProxyServer.Protocol.HTTPS).setProxyHost("127.0.0.1").setProxyPort(port1).setFollowRedirects(true).setUrl(getTargetUrl2())// + .setProxyProtocol(ProxyServer.Protocol.HTTPS)// + .setProxyHost("127.0.0.1")// + .setProxyPort(port1)// + .setFollowRedirects(true)// + .setUrl(getTargetUrl2())// + .setAcceptAnyCertificate(true)// .setHeader("Content-Type", "text/html")// .build(); try { diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index 4df55e2537..cdb6e38cad 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -78,7 +78,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); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 0290789067..2e1d77ee37 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -253,7 +253,7 @@ public void onTimeout(Connection connection) { SSLContext context = clientConfig.getSSLContext(); if (context == null) { try { - context = SslUtils.getInstance().getSSLContext(); + context = SslUtils.getInstance().getSSLContext(clientConfig.isAcceptAnyCertificate()); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 620eb6ea66..9e6a500c63 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -138,6 +138,7 @@ private void doSimpleFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) .setMaxConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); @@ -240,6 +241,7 @@ private void doNonBlockingFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) .setMaxConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 83213da44f..b55ab4721e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -209,10 +209,9 @@ private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException } else { SSLContext sslContext = config.getSSLContext(); - if (sslContext == null) { - sslContext = SslUtils.getInstance().getSSLContext(); - } - + if (sslContext == null) + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); + SSLEngine sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(true); return sslEngine; From 4f34eee9ea12bf16fa1d97ae229b79546fe6f26c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Jun 2014 13:38:24 +0200 Subject: [PATCH 0092/2070] Upgrade Netty 4.0.20 and Javassist 3.18.2 --- providers/netty/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index 3ecc938d35..bc9e908b63 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,12 +39,12 @@ io.netty netty-all - 4.0.19.Final + 4.0.20.Final org.javassist javassist - 3.18.1-GA + 3.18.2-GA From 4beb9c896ec5fbd8e2ebb78f89338ffcfbc5220f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Jun 2014 15:28:15 +0200 Subject: [PATCH 0093/2070] Add host and port to SSLEngine, close #527, close #513 --- .../providers/netty/channel/Channels.java | 33 ++++++------ .../netty/channel/SslInitializer.java | 54 +++++++++++++++++++ .../providers/netty/handler/HttpProtocol.java | 8 ++- 3 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index b55ab4721e..9e546f30da 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -15,11 +15,11 @@ */ package org.asynchttpclient.providers.netty.channel; +import static org.asynchttpclient.providers.netty.handler.Processor.newHttpProcessor; +import static org.asynchttpclient.providers.netty.handler.Processor.newWsProcessor; import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; -import static org.asynchttpclient.providers.netty.handler.Processor.newHttpProcessor; -import static org.asynchttpclient.providers.netty.handler.Processor.newWsProcessor; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -202,20 +202,26 @@ private Timer newNettyTimer() { return nettyTimer; } - private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException { + public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { + SSLEngine sslEngine = null; if (nettyProviderConfig.getSslEngineFactory() != null) { - return nettyProviderConfig.getSslEngineFactory().newSSLEngine(); + sslEngine = nettyProviderConfig.getSslEngineFactory().newSSLEngine(); } else { SSLContext sslContext = config.getSSLContext(); if (sslContext == null) sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); - SSLEngine sslEngine = sslContext.createSSLEngine(); + sslEngine = sslContext.createSSLEngine(peerHost, peerPort); sslEngine.setUseClientMode(true); - return sslEngine; } + + SslHandler sslHandler = new SslHandler(sslEngine); + if (handshakeTimeoutInMillis > 0) + sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); + + return sslHandler; } public void configureProcessor(NettyRequestSender requestSender, AtomicBoolean closed) { @@ -258,13 +264,8 @@ protected void initChannel(Channel ch) throws Exception { @Override protected void initChannel(Channel ch) throws Exception { - SSLEngine sslEngine = createSSLEngine(); - SslHandler sslHandler = new SslHandler(sslEngine); - if (handshakeTimeoutInMillis > 0) - sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); - ChannelPipeline pipeline = ch.pipeline()// - .addLast(SSL_HANDLER, sslHandler)// + .addLast(SSL_HANDLER, new SslInitializer(Channels.this)) .addLast(HTTP_HANDLER, newHttpClientCodec()); if (config.isCompressionEnabled()) { @@ -284,7 +285,7 @@ protected void initChannel(Channel ch) throws Exception { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline()// - .addLast(SSL_HANDLER, new SslHandler(createSSLEngine()))// + .addLast(SSL_HANDLER, new SslInitializer(Channels.this))// .addLast(HTTP_HANDLER, newHttpClientCodec())// .addLast(WS_PROCESSOR, wsProcessor); @@ -330,7 +331,7 @@ public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throw pipeline.remove(SSL_HANDLER); } else if (isSecure) - pipeline.addFirst(SSL_HANDLER, new SslHandler(createSSLEngine())); + pipeline.addFirst(SSL_HANDLER, new SslInitializer(Channels.this)); } protected HttpClientCodec newHttpClientCodec() { @@ -346,7 +347,7 @@ protected HttpClientCodec newHttpClientCodec() { } } - public void upgradeProtocol(ChannelPipeline p, String scheme) throws IOException, GeneralSecurityException { + public void upgradeProtocol(ChannelPipeline p, String scheme, String host, int port) throws IOException, GeneralSecurityException { if (p.get(HTTP_HANDLER) != null) { p.remove(HTTP_HANDLER); } @@ -354,7 +355,7 @@ public void upgradeProtocol(ChannelPipeline p, String scheme) throws IOException if (isSecure(scheme)) { if (p.get(SSL_HANDLER) == null) { p.addFirst(HTTP_HANDLER, newHttpClientCodec()); - p.addFirst(SSL_HANDLER, new SslHandler(createSSLEngine())); + p.addFirst(SSL_HANDLER, createSslHandler(host, port)); } else { p.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java new file mode 100644 index 0000000000..0250f350ac --- /dev/null +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -0,0 +1,54 @@ +/* + * 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 org.asynchttpclient.providers.netty.channel; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import io.netty.handler.ssl.SslHandler; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +/** + * On connect, replaces itself with a SslHandler that has a SSLEngine configured with the remote host and port. + * + * @author slandelle + */ +public class SslInitializer extends ChannelOutboundHandlerAdapter { + + private final Channels channels; + + public SslInitializer(Channels channels) { + this.channels = channels; + new Exception().printStackTrace(); + } + + @Override + public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) + throws Exception { + + InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) remoteAddress; + String peerHost = remoteInetSocketAddress.getHostName(); + int peerPort = remoteInetSocketAddress.getPort(); + + SslHandler sslHandler = channels.createSslHandler(peerHost, peerPort); + + ctx.pipeline().replace(Channels.SSL_HANDLER, Channels.SSL_HANDLER, sslHandler); + + ctx.connect(remoteAddress, localAddress, promise); + } +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 57f81b6142..044b3b3316 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -347,7 +347,13 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques try { LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, request.getUrl()); - channels.upgradeProtocol(channel.pipeline(), request.getURI().getScheme()); + + URI requestURI = request.getURI(); + String scheme = requestURI.getScheme(); + String host = AsyncHttpProviderUtils.getHost(requestURI); + int port = AsyncHttpProviderUtils.getPort(requestURI); + + channels.upgradeProtocol(channel.pipeline(), scheme, host, port); } catch (Throwable ex) { channels.abort(future, ex); } From f486d7b3ef6fe5879006a458cd07ab3a2c52d303 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Jun 2014 15:43:47 +0200 Subject: [PATCH 0094/2070] unused import --- .../providers/netty/request/NettyConnectListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index c023406e44..45f5ef4bfc 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -33,7 +33,6 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLSession; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; From 1a3c9a966bc732e908e11523abfcddbb72e8d5d5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Jun 2014 15:46:35 +0200 Subject: [PATCH 0095/2070] woups --- .../asynchttpclient/providers/netty/channel/SslInitializer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java index 0250f350ac..e0df603cd0 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -34,7 +34,6 @@ public class SslInitializer extends ChannelOutboundHandlerAdapter { public SslInitializer(Channels channels) { this.channels = channels; - new Exception().printStackTrace(); } @Override From 26b588383218777ac96f77379bc61c7ded570f31 Mon Sep 17 00:00:00 2001 From: Lukasz Kryger Date: Sat, 14 Jun 2014 22:48:08 +0100 Subject: [PATCH 0096/2070] Minor fix in the contributing section of README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07afb045d3..3e59fffe30 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ Here a the few rules we'd like you to respect if you do so: * Use a 140 chars line max length * Don't use * imports * Stick to the org, com, javax, java imports order -* Your PR can contain multiple commits when submitting, but once it's been reviewed, we'll ask you to squash the them into a single once +* Your PR can contain multiple commits when submitting, but once it's been reviewed, we'll ask you to squash them into a single one * Regarding licensing: * You must be the original author of the code you suggest. * If not, you have to prove that the original code was published under Apache License 2 and properly mention original copyrights. From 99e139103bbf92faf48de77ac6c26657fa92aed6 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 17 Jun 2014 01:32:25 -0700 Subject: [PATCH 0097/2070] [master] + fix issue #1691 https://java.net/jira/browse/GRIZZLY-1691 "Support RFC 7238, HTTP Status Code "308 Permanent Redirect"" --- providers/grizzly/pom.xml | 2 +- .../org/asynchttpclient/providers/grizzly/EventHandler.java | 5 ++++- .../providers/grizzly/statushandler/RedirectHandler.java | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/providers/grizzly/pom.xml b/providers/grizzly/pom.xml index 9de0ff62a0..b55f00865e 100644 --- a/providers/grizzly/pom.xml +++ b/providers/grizzly/pom.xml @@ -14,7 +14,7 @@ - 2.3.13 + 2.3.14 1.1 diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index ec251b8955..934bc52bc4 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -65,7 +65,9 @@ public final class EventHandler { HANDLER_MAP.put(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407.getStatusCode(), ProxyAuthorizationHandler.INSTANCE); HANDLER_MAP.put(HttpStatus.MOVED_PERMANENTLY_301.getStatusCode(), 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); } private final AsyncHttpClientConfig config; @@ -405,7 +407,8 @@ public 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); } // ----------------------------------------------------- Private Methods diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java index c7bd5d514b..5d914b0f75 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.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. @@ -94,7 +94,8 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT private boolean sendAsGet(final HttpResponsePacket response, final HttpTxContext ctx) { final int statusCode = response.getStatus(); - return !(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && ctx.getProvider().getClientConfig().isStrict302Handling()); + return !(statusCode < 302 || statusCode > 303) && + !(statusCode == 302 && ctx.getProvider().getClientConfig().isStrict302Handling()); } } // END RedirectHandler From c04abace94cd6f14c5174235355e77eaf6ff891b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 17 Jun 2014 10:38:30 +0200 Subject: [PATCH 0098/2070] Bump 1.8.11 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e59fffe30..539576791c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.10 + 1.8.11 ``` From 5c3ae9b8e85c41343dd2b93c2069a4f9c7b9b89d Mon Sep 17 00:00:00 2001 From: salilsurendran Date: Tue, 17 Jun 2014 20:51:06 -0700 Subject: [PATCH 0099/2070] Making minor changes --- .../AsyncHttpClientConfigDefaults.java | 8 +- .../org/asynchttpclient/util/MiscUtil.java | 96 ++++++++++--------- .../asynchttpclient/util/MiscUtilTest.java | 56 +++++------ 3 files changed, 83 insertions(+), 77 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 16818d1aa9..bfaae5cb56 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -17,15 +17,13 @@ import static org.asynchttpclient.util.MiscUtil.getBooleanValue; import static org.asynchttpclient.util.MiscUtil.getIntValue; import org.asynchttpclient.util.DefaultHostnameVerifier; + import javax.net.ssl.HostnameVerifier; -import org.asynchttpclient.util.DefaultHostnameVerifier; -import static org.asynchttpclient.util.MiscUtil.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + public final class AsyncHttpClientConfigDefaults { - + private AsyncHttpClientConfigDefaults() { } diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 486140035b..060d603f84 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -21,8 +21,8 @@ public class MiscUtil { - - public final static Logger logger = LoggerFactory.getLogger(MiscUtil.class); + + public final static Logger logger = LoggerFactory.getLogger(MiscUtil.class); private MiscUtil() { } @@ -47,51 +47,59 @@ public static boolean isNonEmpty(Map map) { return map != null && !map.isEmpty(); } + //The getBooleanValue() method replaces this and reads the property from properties file + //too. Plus has a better check for invalid boolean values. /* public static boolean getBoolean(String systemPropName, boolean defaultValue) { String systemPropValue = System.getProperty(systemPropName); return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; }*/ - public static Integer getIntValue(String property,int defaultValue){ - //Read system property and if not null return that. - Integer value = Integer.getInteger(property); - if(value != null) - return value; - Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - if(asyncHttpClientConfigProperties!=null){ - String valueString=asyncHttpClientConfigProperties.getProperty(property); - try{ - //If property is present and is non null parse it. - if(valueString != null) - return Integer.parseInt(valueString); - }catch(NumberFormatException e){ - //If property couldn't be parsed log the error message and return default value. - logger.error("Property : " + property + " has value = " + valueString + - " which couldn't be parsed to an int value. Returning default value: " + defaultValue,e); - } - } - return defaultValue; - } - - public static Boolean getBooleanValue(String property,boolean defaultValue){ - String value = System.getProperty(property); - Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - //If system property is invalid and property file is present then read value - //from property file - if(!MiscUtil.isValidBooleanValue(value) && asyncHttpClientConfigProperties!=null) - value=asyncHttpClientConfigProperties.getProperty(property); - //If valid value has been found return that value - if(MiscUtil.isValidBooleanValue(value)) - return Boolean.parseBoolean(value); - //If a value has been specified but can't be parsed into a boolean log a message - //stating that value is unparseable and default values are being used. - if(value != null) - logger.error("Property : " + property + " has value = " + value + - " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); - return defaultValue; - } - - private static boolean isValidBooleanValue(String value){ - return value != null && ("true".equalsIgnoreCase(value)||"false".equalsIgnoreCase(value)); - } + public static Integer getIntValue(String property,int defaultValue){ + //Read system property and if not null return that. + Integer value = Integer.getInteger(property); + if(value != null) + return value; + Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); + if(asyncHttpClientConfigProperties!=null){ + String valueString=asyncHttpClientConfigProperties.getProperty(property); + try{ + //If property is present and is non null parse it. + if(valueString != null) + return Integer.parseInt(valueString); + }catch(NumberFormatException e){ + //If property couldn't be parsed log the error message and return default value. + logger.error("Property : " + property + " has value = " + valueString + + " which couldn't be parsed to an int value. Returning default value: " + defaultValue,e); + } + } + return defaultValue; + } + + private static boolean isValidBooleanValue(String value){ + return value != null && ("true".equalsIgnoreCase(value)||"false".equalsIgnoreCase(value)); + } + + public static Boolean getBooleanValue(String property,boolean defaultValue){ + + // get from System property first + String value = System.getProperty(property); + if(isValidBooleanValue(value)) + return Boolean.parseBoolean(value); + + // get from property file + Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); + if(asyncHttpClientConfigProperties!=null){ + value=asyncHttpClientConfigProperties.getProperty(property); + if(isValidBooleanValue(value)) + return Boolean.parseBoolean(value); + } + + //have to use the default value now + if(value != null) + logger.error("Property : " + property + " has value = " + value + + " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); + + return defaultValue; + } + } diff --git a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java index 52b698b40e..695ec1f829 100644 --- a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java +++ b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java @@ -44,35 +44,35 @@ public void testGetIntegerValue() { System.clearProperty(MY_SPECIAL_INT_PROPERTY); } - @Test - public void testGetBooleanValue() { - // Setup a AsyncImplHelperMock that returns a mock - // asynchttpclient.properties with a value - // set for 'my.special.int.property' property - Properties properties = new Properties(); - properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "true"); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + @Test + public void testGetBooleanValue() { + // Setup a AsyncImplHelperMock that returns a mock + // asynchttpclient.properties with a value + // set for 'my.special.int.property' property + Properties properties = new Properties(); + properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "true"); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getBooleanValue() method returns TRUE - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - // Set a system property that overrides the value in the - // asynchttpclient.properties - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "false"); - // Assert false is returned, i.e. system property takes precedence over - // property in asynchttpclient.properties - Assert.assertFalse(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Clear the system property - System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); - // Assert that the value set in asynchttpclient.properties is returned - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that the value set in asynchttpclient.properties is returned - // even though corrupt system property is set. - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); - } + + // Assert that the getBooleanValue() method returns TRUE + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + // Set a system property that overrides the value in the + // asynchttpclient.properties + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "false"); + // Assert false is returned, i.e. system property takes precedence over + // property in asynchttpclient.properties + Assert.assertFalse(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Clear the system property + System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); + // Assert that the value set in asynchttpclient.properties is returned + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that the value set in asynchttpclient.properties is returned + // even though corrupt system property is set. + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); + } @Test public void testGetDefaultIntegerValue() { From d677d01e51a89c28f511dda40aeee0e484c64230 Mon Sep 17 00:00:00 2001 From: salilsurendran Date: Thu, 19 Jun 2014 11:56:28 -0700 Subject: [PATCH 0100/2070] Committing to fix formatting and indentation issues. --- .../org/asynchttpclient/util/MiscUtil.java | 72 +++++----- .../AsyncHttpClientConfigBuilderTest.java | 30 ++-- .../asynchttpclient/AsyncImplHelperMock.java | 22 +-- .../asynchttpclient/util/MiscUtilTest.java | 132 +++++++++--------- pom.xml | 24 ++-- 5 files changed, 138 insertions(+), 142 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 060d603f84..d7092bdf42 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -18,8 +18,6 @@ import java.util.Map; import java.util.Properties; - - public class MiscUtil { public final static Logger logger = LoggerFactory.getLogger(MiscUtil.class); @@ -47,59 +45,63 @@ public static boolean isNonEmpty(Map map) { return map != null && !map.isEmpty(); } - //The getBooleanValue() method replaces this and reads the property from properties file - //too. Plus has a better check for invalid boolean values. - /* public static boolean getBoolean(String systemPropName, boolean defaultValue) { - String systemPropValue = System.getProperty(systemPropName); - return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; - }*/ - - public static Integer getIntValue(String property,int defaultValue){ - //Read system property and if not null return that. + // The getBooleanValue() method replaces this and reads the property from + // properties file + // too. Plus has a better check for invalid boolean values. + /* + * public static boolean getBoolean(String systemPropName, boolean + * defaultValue) { String systemPropValue = + * System.getProperty(systemPropName); return systemPropValue != null ? + * systemPropValue.equalsIgnoreCase("true") : defaultValue; } + */ + + public static Integer getIntValue(String property, int defaultValue) { + // Read system property and if not null return that. Integer value = Integer.getInteger(property); - if(value != null) + if (value != null) return value; Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - if(asyncHttpClientConfigProperties!=null){ - String valueString=asyncHttpClientConfigProperties.getProperty(property); - try{ - //If property is present and is non null parse it. - if(valueString != null) + if (asyncHttpClientConfigProperties != null) { + String valueString = asyncHttpClientConfigProperties.getProperty(property); + try { + // If property is present and is non null parse it. + if (valueString != null) return Integer.parseInt(valueString); - }catch(NumberFormatException e){ - //If property couldn't be parsed log the error message and return default value. - logger.error("Property : " + property + " has value = " + valueString + - " which couldn't be parsed to an int value. Returning default value: " + defaultValue,e); + } catch (NumberFormatException e) { + // If property couldn't be parsed log the error message and + // return default value. + logger.error("Property : " + property + " has value = " + valueString + + " which couldn't be parsed to an int value. Returning default value: " + defaultValue, e); } } return defaultValue; } - private static boolean isValidBooleanValue(String value){ - return value != null && ("true".equalsIgnoreCase(value)||"false".equalsIgnoreCase(value)); + private static boolean isValidBooleanValue(String value) { + return value != null && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)); } - public static Boolean getBooleanValue(String property,boolean defaultValue){ + public static Boolean getBooleanValue(String property, boolean defaultValue) { // get from System property first String value = System.getProperty(property); - if(isValidBooleanValue(value)) - return Boolean.parseBoolean(value); + if (isValidBooleanValue(value)) + return Boolean.parseBoolean(value); // get from property file Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - if(asyncHttpClientConfigProperties!=null){ - value=asyncHttpClientConfigProperties.getProperty(property); - if(isValidBooleanValue(value)) - return Boolean.parseBoolean(value); + if (asyncHttpClientConfigProperties != null) { + value = asyncHttpClientConfigProperties.getProperty(property); + if (isValidBooleanValue(value)) + return Boolean.parseBoolean(value); } - //have to use the default value now - if(value != null) - logger.error("Property : " + property + " has value = " + value + - " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); + // have to use the default value now + if (value != null) + logger.error("Property : " + property + " has value = " + value + + " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); return defaultValue; - } + } } diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java b/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java index 02d532f3d4..44818fb541 100644 --- a/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java @@ -3,28 +3,28 @@ import org.testng.Assert; import org.testng.annotations.Test; -public class AsyncHttpClientConfigBuilderTest { - +public class AsyncHttpClientConfigBuilderTest { + @Test - public void testDefaultConfigValues(){ + public void testDefaultConfigValues() { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); - Assert.assertEquals(config.getConnectionTimeoutInMs(),60000); - Assert.assertEquals(config.getRequestTimeoutInMs(),60000); - Assert.assertEquals(config.getIdleConnectionTimeoutInMs(),60000); + Assert.assertEquals(config.getConnectionTimeoutInMs(), 60000); + Assert.assertEquals(config.getRequestTimeoutInMs(), 60000); + Assert.assertEquals(config.getIdleConnectionTimeoutInMs(), 60000); Assert.assertFalse(config.isCompressionEnabled()); Assert.assertFalse(config.isRedirectEnabled()); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"connectionTimeoutInMs","1000"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"requestTimeoutInMs","500"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"compressionEnabled","true"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"redirectsEnabled","true"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "connectionTimeoutInMs", "1000"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "requestTimeoutInMs", "500"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "compressionEnabled", "true"); + System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "redirectsEnabled", "true"); config = new AsyncHttpClientConfig.Builder().build(); - Assert.assertEquals(config.getConnectionTimeoutInMs(),1000); + Assert.assertEquals(config.getConnectionTimeoutInMs(), 1000); Assert.assertEquals(config.getRequestTimeoutInMs(), 500); Assert.assertTrue(config.isCompressionEnabled()); Assert.assertTrue(config.isRedirectEnabled()); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"connectionTimeoutInMs"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"requestTimeoutInMs"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"compressionEnabled"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT+"defaultRedirectsEnabled"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "connectionTimeoutInMs"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "requestTimeoutInMs"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "compressionEnabled"); + System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "defaultRedirectsEnabled"); } } diff --git a/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java b/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java index 562af7a3dd..e9f18af883 100644 --- a/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java +++ b/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java @@ -8,16 +8,16 @@ import org.asynchttpclient.util.AsyncImplHelper; public class AsyncImplHelperMock extends MockUp { - - private static Properties properties; - - public AsyncImplHelperMock(Properties properties){ - this.properties=properties; - } - - @Mock - public Properties getAsyncImplProperties() { - return properties; - } + + private static Properties properties; + + public AsyncImplHelperMock(Properties properties) { + this.properties = properties; + } + + @Mock + public Properties getAsyncImplProperties() { + return properties; + } } diff --git a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java index 695ec1f829..794090f43e 100644 --- a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java +++ b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java @@ -7,14 +7,13 @@ import org.testng.annotations.Test; public class MiscUtilTest { - private final Integer MY_SPECIAL_INT_VALUE = 10; - private final Integer MY_SPECIAL_SYSTEM_INT_VALUE = 100; - private final String MY_SPECIAL_INT_PROPERTY = "my.special.int.property"; + private final Integer MY_SPECIAL_INT_VALUE = 10; + private final Integer MY_SPECIAL_SYSTEM_INT_VALUE = 100; + private final String MY_SPECIAL_INT_PROPERTY = "my.special.int.property"; private final String MY_SPECIAL_BOOLEAN_PROPERTY = "my.special.boolean.property"; private final Integer MY_SPECIAL_INT_DEFAULT_VALUE = -100; - - @Test + @Test public void testGetIntegerValue() { // Setup a AsyncImplHelperMock that returns a mock // asynchttpclient.properties with a value @@ -23,7 +22,6 @@ public void testGetIntegerValue() { properties.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_VALUE.toString()); AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - // Assert that the getIntValue() method returns 10 Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); // Set a system property that overrides the value in the @@ -31,7 +29,7 @@ public void testGetIntegerValue() { System.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_SYSTEM_INT_VALUE.toString()); // Assert 100 is returned, i.e. system property takes precedence over // property in asynchttpclient.properties - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1),MY_SPECIAL_SYSTEM_INT_VALUE); + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_SYSTEM_INT_VALUE); // Clear the system property System.clearProperty(MY_SPECIAL_INT_PROPERTY); // Assert that the value set in asynchttpclient.properties is returned @@ -43,8 +41,8 @@ public void testGetIntegerValue() { Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); System.clearProperty(MY_SPECIAL_INT_PROPERTY); } - - @Test + + @Test public void testGetBooleanValue() { // Setup a AsyncImplHelperMock that returns a mock // asynchttpclient.properties with a value @@ -53,7 +51,6 @@ public void testGetBooleanValue() { properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "true"); AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - // Assert that the getBooleanValue() method returns TRUE Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); // Set a system property that overrides the value in the @@ -73,66 +70,63 @@ public void testGetBooleanValue() { Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); } - - @Test - public void testGetDefaultIntegerValue() { - - // Assert that the getIntValue() method returns the default value if - // Properties is not present - Assert.assertEquals( - MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), - MY_SPECIAL_INT_DEFAULT_VALUE); - // Setup up a mock of a asynchttpclient.properties that initially is empty - Properties properties = new Properties(); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getIntValue() method returns the default value if there is no - // property set in the asynchttpclient.properties - Assert.assertEquals( - MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), - MY_SPECIAL_INT_DEFAULT_VALUE); - //Now set a corrupt value in the asynchttpclient.properties - properties.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that the getIntValue() method returns the default value if there is a corrupt - // property set in the asynchttpclient.properties - Assert.assertEquals( - MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), - MY_SPECIAL_INT_DEFAULT_VALUE); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is - //returned - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), - MY_SPECIAL_INT_DEFAULT_VALUE); - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - } + @Test + public void testGetDefaultIntegerValue() { + + // Assert that the getIntValue() method returns the default value if + // Properties is not present + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); + // Setup up a mock of a asynchttpclient.properties that initially is + // empty + Properties properties = new Properties(); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - - @Test - public void testGetDefaultBooleanValue() { - // Assert that the getBooleanValue() method returns the default value if - // asynchttpclient.properties is not present - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Setup up a mock of a asynchttpclient.properties that initially is empty - Properties properties = new Properties(); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + // Assert that the getIntValue() method returns the default value if + // there is no + // property set in the asynchttpclient.properties + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); + // Now set a corrupt value in the asynchttpclient.properties + properties.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); + // Assert that the getIntValue() method returns the default value if + // there is a corrupt + // property set in the asynchttpclient.properties + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); + // Assert that even though values set in asynchttpclient.properties and + // system property is corrupt the default value is + // returned + Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + } - - // Assert that the getBooleanValue() method returns the default value if there is no - // property set in the asynchttpclient.properties - Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - //Now set a corrupt value in the asynchttpclient.properties - properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that the getBooleanValue() method returns the default value if there is a corrupt - // property set in the asynchttpclient.properties - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and system property is corrupt the default value is - //returned - Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - } + @Test + public void testGetDefaultBooleanValue() { + // Assert that the getBooleanValue() method returns the default value if + // asynchttpclient.properties is not present + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Setup up a mock of a asynchttpclient.properties that initially is + // empty + Properties properties = new Properties(); + AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); + + // Assert that the getBooleanValue() method returns the default value if + // there is no + // property set in the asynchttpclient.properties + Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + // Now set a corrupt value in the asynchttpclient.properties + properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that the getBooleanValue() method returns the default value if + // there is a corrupt + // property set in the asynchttpclient.properties + Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); + // Set a corrupt system property + System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); + // Assert that even though values set in asynchttpclient.properties and + // system property is corrupt the default value is + // returned + Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); + System.clearProperty(MY_SPECIAL_INT_PROPERTY); + } } diff --git a/pom.xml b/pom.xml index 47d662b815..4df2c85397 100644 --- a/pom.xml +++ b/pom.xml @@ -514,17 +514,17 @@ test - com.e-movimento.tinytools - privilegedaccessor - ${privilegedaccessor.version} - test - - - com.googlecode.jmockit - jmockit - ${jmockit.version} - test - + com.e-movimento.tinytools + privilegedaccessor + ${privilegedaccessor.version} + test + + + com.googlecode.jmockit + jmockit + ${jmockit.version} + test + http://oss.sonatype.org/content/repositories/snapshots @@ -539,7 +539,7 @@ 6.0.29 2.4 1.3 - 1.5 + 1.5 1.2.2 From c5e9d8f7bf99f56d0e76f75a8a934cd126939664 Mon Sep 17 00:00:00 2001 From: Eugene Ivakhno Date: Fri, 20 Jun 2014 14:55:54 +0300 Subject: [PATCH 0101/2070] fixed realm URI computation for the case of non absolute uri, null query, and not omit query --- .../asynchttpclient/providers/netty/handler/HttpProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 044b3b3316..d0de464588 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -220,7 +220,7 @@ private final String computeRealmURI(Realm realm, URI requestURI) throws URISynt return requestURI.toString(); } } else { - if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { + if (realm.isOmitQuery() || !isNonEmpty(requestURI.getQuery())) { return requestURI.getPath(); } else { return requestURI.getPath() + "?" + requestURI.getQuery(); From 9fdf6e79bff1b863c7a8bfba2f57daed8da82ddb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 09:47:16 +0200 Subject: [PATCH 0102/2070] typo --- api/src/main/java/org/asynchttpclient/Request.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 248f6e5e5e..a54b96f32f 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -126,9 +126,9 @@ public interface Request { BodyGenerator getBodyGenerator(); /** - * Return the current size of the content-lenght header based on the body's size. + * Return the current size of the content-length header based on the body's size. * - * @return the current size of the content-lenght header based on the body's size. + * @return the current size of the content-length header based on the body's size. */ long getContentLength(); From e5f188aaaef43f2eca45f5ccdc6548d7d32f6f4f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 10:43:06 +0200 Subject: [PATCH 0103/2070] Fix Fluent(CaseInsensitiveStrings)Map.add javadoc, close #581 --- .../asynchttpclient/FluentCaseInsensitiveStringsMap.java | 3 +-- api/src/main/java/org/asynchttpclient/FluentStringsMap.java | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java index 77a9e4e20f..c5417797e9 100644 --- a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/FluentStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java index 336ffbbc97..a8fa9e1a77 100644 --- a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/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 f7492801957848e38d6f304a0c3d18a05a278cd3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 10:46:59 +0200 Subject: [PATCH 0104/2070] Optimize Fluent(CaseInsensitive)StringsMap for single value, close #580 --- .../FluentCaseInsensitiveStringsMap.java | 20 +++++++++++++++++++ .../org/asynchttpclient/FluentStringsMap.java | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java index c5417797e9..0b9b1ad192 100644 --- a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/FluentStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java index a8fa9e1a77..34cc5ff237 100644 --- a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/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 2694692806e26ea5e73b5e010f0c28dfa759b9ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 12:54:00 +0200 Subject: [PATCH 0105/2070] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 539576791c..fab0cd307c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.11 + 1.8.12 ``` From a2bcccf88dbd22be5a52913c4016f7107ed1b49a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 17:20:11 +0200 Subject: [PATCH 0106/2070] minor clean up --- .../main/java/org/asynchttpclient/ProxyServer.java | 2 +- .../util/AsyncHttpProviderUtils.java | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/ProxyServer.java b/api/src/main/java/org/asynchttpclient/ProxyServer.java index f5c2f6e458..171c6f6238 100644 --- a/api/src/main/java/org/asynchttpclient/ProxyServer.java +++ b/api/src/main/java/org/asynchttpclient/ProxyServer.java @@ -66,7 +66,7 @@ public ProxyServer(final Protocol protocol, final String host, final int port, S this.port = port; this.principal = principal; this.password = password; - this.uri = AsyncHttpProviderUtils.createUri(toString()); + this.uri = AsyncHttpProviderUtils.createNonEmptyPathURI(toString()); } public ProxyServer(final String host, final int port, String principal, String password) { diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 386319b2a9..6a7bb09cc4 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -48,7 +48,7 @@ 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); @@ -64,10 +64,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(); @@ -202,8 +198,7 @@ public static String parseCharset(String contentType) { // Quite a lot of sites have charset="CHARSET", // e.g. charset="utf-8". Note the quotes. This is // not correct, but client should be able to handle - // it (all browsers do, Apache HTTP Client and Grizzly - // strip it by default) + // it (all browsers do, Grizzly strips it by default) // This is a poor man's trim("\"").trim("'") return charset.replaceAll("\"", "").replaceAll("'", ""); } @@ -212,11 +207,6 @@ public static String parseCharset(String contentType) { return null; } - public static int secondsFromNow(long timeMillis) { - long maxAgeMillis = timeMillis - System.currentTimeMillis(); - return (int) (maxAgeMillis / 1000) + (maxAgeMillis % 1000 != 0 ? 1 : 0); - } - public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { return config.getAllowPoolingConnection() ? "keep-alive" : "close"; } From a2d323e106544853387714be6e6ee165d81162db Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 17:23:15 +0200 Subject: [PATCH 0107/2070] Upgrade Netty 4.0.21 --- providers/netty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index bc9e908b63..d6abb3a8ef 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,7 +39,7 @@ io.netty netty-all - 4.0.20.Final + 4.0.21.Final org.javassist From a89885558fa03bfc9d7e2a39ddbac149edc42a0b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 18:49:23 +0200 Subject: [PATCH 0108/2070] Port missing #540 on master --- .../asynchttpclient/RequestBuilderBase.java | 33 +++++++++++++++++-- .../async/RequestBuilderTest.java | 8 +++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 01f0eaea05..0d7dc1df29 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -634,8 +634,7 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe 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) */ @@ -647,8 +646,28 @@ public Request build() { url = url.substring(0, i); } signatureCalculator.calculateAndAddSignature(url, request, this); + } + } + + private void computeRequestCharset() { + 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 + } } - + } + + private void computeRequestContentLength() { if (request.length < 0 && request.streamData == null) { // can't concatenate content-length String contentLength = null; @@ -664,6 +683,14 @@ public Request build() { } } } + } + + public Request build() { + + executeSignatureCalculator(); + computeRequestCharset(); + computeRequestContentLength(); + if (request.cookies != null) { request.cookies = Collections.unmodifiableCollection(request.cookies); } diff --git a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java index d4d3d8cd0b..a6e9214ab4 100644 --- a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java @@ -112,4 +112,12 @@ public void testPercentageEncodedUserInfo() { assertEquals(req.getMethod(), "GET"); 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"); + } } From 1d5392e9c11f54a8b06cd0f62a063fe0649c95d8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 19:32:18 +0200 Subject: [PATCH 0109/2070] Remove useless calls to Request.getUrl, close #582 --- .../asynchttpclient/resumable/ResumableAsyncHandler.java | 5 +++-- .../asynchttpclient/providers/netty/channel/Channels.java | 4 ++-- .../providers/netty/handler/HttpProtocol.java | 7 +++---- .../asynchttpclient/providers/netty/handler/Protocol.java | 2 +- .../providers/netty/request/NettyRequestSender.java | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index 2463186d4c..53101d590a 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -197,8 +197,9 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws */ public Request adjustRequestRange(Request request) { - if (resumableIndex.get(request.getUrl()) != null) { - byteTransferred.set(resumableIndex.get(request.getUrl())); + Long ri = resumableIndex.get(request.getUrl()); + if (ri != null) { + byteTransferred.set(ri); } // The Resumbale diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 9e546f30da..0045be2233 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -296,8 +296,8 @@ protected void initChannel(Channel ch) throws Exception { }); } - public Bootstrap getBootstrap(String url, boolean useSSl, boolean useProxy) { - return (url.startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) + public Bootstrap getBootstrap(URI uri, boolean useSSl, boolean useProxy) { + return (uri.getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index d0de464588..436d16ea3f 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -257,7 +257,7 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); - LOGGER.debug("Sending authentication to {}", request.getUrl()); + LOGGER.debug("Sending authentication to {}", request.getURI()); Callback callback = new Callback(future) { public void call() throws Exception { channels.drainChannel(channel, future); @@ -302,7 +302,7 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null) { List proxyAuthenticateHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); if (!proxyAuthenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { - LOGGER.debug("Sending proxy authentication to {}", request.getUrl()); + LOGGER.debug("Sending proxy authentication to {}", request.getURI()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; @@ -346,10 +346,9 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques } try { - LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, request.getUrl()); - URI requestURI = request.getURI(); String scheme = requestURI.getScheme(); + LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); String host = AsyncHttpProviderUtils.getHost(requestURI); int port = AsyncHttpProviderUtils.getPort(requestURI); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 2ac8553440..7f9032cb9a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -117,7 +117,7 @@ protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future.setURI(uri); String newUrl = uri.toString(); - if (request.getUrl().startsWith(WEBSOCKET)) { + if (request.getURI().getScheme().startsWith(WEBSOCKET)) { newUrl = newUrl.replaceFirst(HTTP, WEBSOCKET); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 57e1210f65..48d6cfb3de 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -219,7 +219,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? boolean acquiredConnection = !reclaimCache && channels.acquireConnection(asyncHandler); - Bootstrap bootstrap = channels.getBootstrap(request.getUrl(), useSSl, useProxy); + Bootstrap bootstrap = channels.getBootstrap(request.getURI(), useSSl, useProxy); NettyConnectListener connectListener = new NettyConnectListener(config, this, future); @@ -349,7 +349,7 @@ public ListenableFuture sendRequest(final Request request,// } // FIXME really useful? Why not do this check when building the request? - if (request.getUrl().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { + if (request.getURI().getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { throw new IOException("WebSocket method must be a GET"); } From 186a9d090de21e19ff4e4f7d1eae1aeaa207c0ea Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 20:20:53 +0200 Subject: [PATCH 0110/2070] Fix build --- api/src/main/java/org/asynchttpclient/RequestBuilderBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 0d7dc1df29..fa213378e4 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -650,7 +650,7 @@ private void executeSignatureCalculator() { } private void computeRequestCharset() { - if (request.charset != null) { + if (request.charset == null) { try { final String contentType = request.headers.getFirstValue("Content-Type"); if (contentType != null) { From 62336576cd7954812feedba834a63488a7a0ecd3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 21:29:08 +0200 Subject: [PATCH 0111/2070] Lazy init Request cookies list, add set(Collection) method, close #584 --- .../asynchttpclient/RequestBuilderBase.java | 97 ++++++++----------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index fa213378e4..4a881f0fa5 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -57,7 +57,7 @@ private static final class RequestImpl implements Request { private InetAddress address; private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers; - private Collection cookies; + private ArrayList cookies; private byte[] byteData; private String stringData; private InputStream streamData; @@ -227,10 +227,7 @@ public boolean hasHeaders() { @Override public Collection getCookies() { - if (cookies == null) { - cookies = Collections.unmodifiableCollection(Collections. emptyList()); - } - return cookies; + return cookies != null ? Collections.unmodifiableCollection(cookies) : Collections. emptyList(); } @Override @@ -460,16 +457,14 @@ public T addHeader(String name, String value) { } public T setHeaders(FluentCaseInsensitiveStringsMap headers) { - if (headers != null) { + if (headers != null) request.headers = new FluentCaseInsensitiveStringsMap(headers); - } return derived.cast(this); } public T setHeaders(Map> headers) { - if (headers != null) { + if (headers != null) request.headers = new FluentCaseInsensitiveStringsMap(headers); - } return derived.cast(this); } @@ -478,20 +473,45 @@ public T setContentLength(int length) { return derived.cast(this); } + private void lazyInitCookies() { + if (request.cookies == null) + request.cookies = new ArrayList(3); + } + public T addCookie(Cookie cookie) { - if (request.cookies == null) { - request.cookies = new ArrayList(); - } + lazyInitCookies(); request.cookies.add(cookie); return derived.cast(this); } - public void resetQueryParameters() { - request.queryParams = null; + public void resetCookies() { + if (request.cookies != null) + request.cookies.clear(); } - public void resetCookies() { - request.cookies.clear(); + 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 resetQueryParameters() { + request.queryParams = null; } public void resetParameters() { @@ -544,28 +564,22 @@ public T setBody(BodyGenerator bodyGenerator) { } public T addQueryParameter(String name, String value) { - if (request.queryParams == null) { + if (request.queryParams == null) request.queryParams = new FluentStringsMap(); - } request.queryParams.add(name, value); return derived.cast(this); } public T setQueryParameters(FluentStringsMap parameters) { - if (parameters == null) { - request.queryParams = null; - } else { - request.queryParams = new FluentStringsMap(parameters); - } + request.queryParams = parameters != null? new FluentStringsMap(parameters) : null; return derived.cast(this); } public T addParameter(String key, String value) { resetNonMultipartData(); resetMultipartData(); - if (request.params == null) { + if (request.params == null) request.params = new FluentStringsMap(); - } request.params.add(key, value); return derived.cast(this); } @@ -587,9 +601,8 @@ public T setParameters(Map> parameters) { public T addBodyPart(Part part) { resetParameters(); resetNonMultipartData(); - if (request.parts == null) { + if (request.parts == null) request.parts = new ArrayList(); - } request.parts.add(part); return derived.cast(this); } @@ -686,39 +699,9 @@ private void computeRequestContentLength() { } public Request build() { - executeSignatureCalculator(); computeRequestCharset(); computeRequestContentLength(); - - if (request.cookies != null) { - request.cookies = Collections.unmodifiableCollection(request.cookies); - } return request; } - - public T addOrReplaceCookie(Cookie cookie) { - String cookieKey = cookie.getName(); - boolean replace = false; - int index = 0; - if (request.cookies == null) { - request.cookies = new ArrayList(); - request.cookies.add(cookie); - return derived.cast(this); - } - 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 b11c7e3934b86dccd7222878b409d6df3bbd501a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 11:07:26 +0200 Subject: [PATCH 0112/2070] Revert "Pick up default config values from asynchttpclient.properties file" --- .../AsyncHttpClientConfigDefaults.java | 57 ++++---- .../asynchttpclient/util/AsyncImplHelper.java | 2 +- .../org/asynchttpclient/util/MiscUtil.java | 68 +-------- .../AsyncHttpClientConfigBuilderTest.java | 30 ---- .../asynchttpclient/AsyncImplHelperMock.java | 23 --- .../asynchttpclient/util/MiscUtilTest.java | 132 ------------------ pom.xml | 17 +-- 7 files changed, 35 insertions(+), 294 deletions(-) delete mode 100644 api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java delete mode 100644 api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java delete mode 100644 api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index edbc0c37eb..3cb9ebddc7 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -12,66 +12,61 @@ */ package org.asynchttpclient; +import static org.asynchttpclient.util.MiscUtil.getBoolean; - -import static org.asynchttpclient.util.MiscUtil.getBooleanValue; -import static org.asynchttpclient.util.MiscUtil.getIntValue; import org.asynchttpclient.util.DefaultHostnameVerifier; 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 getIntValue(ASYNC_CLIENT + "maxTotalConnections", -1); + return Integer.getInteger(ASYNC_CLIENT + "maxTotalConnections", -1); } public static int defaultMaxConnectionPerHost() { - return getIntValue(ASYNC_CLIENT + "maxConnectionsPerHost", -1); + return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); } public static int defaultConnectionTimeOutInMs() { - return getIntValue(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); + return Integer.getInteger(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); } public static int defaultIdleConnectionInPoolTimeoutInMs() { - return getIntValue(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); + return Integer.getInteger(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); } public static int defaultIdleConnectionTimeoutInMs() { - return getIntValue(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); + return Integer.getInteger(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); } public static int defaultRequestTimeoutInMs() { - return getIntValue(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); + return Integer.getInteger(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); } public static int defaultWebSocketIdleTimeoutInMs() { - return getIntValue(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); + return Integer.getInteger(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); } public static int defaultMaxConnectionLifeTimeInMs() { - return getIntValue(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); + return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); } public static boolean defaultRedirectEnabled() { - return getBooleanValue(ASYNC_CLIENT + "redirectsEnabled",false); + return Boolean.getBoolean(ASYNC_CLIENT + "redirectsEnabled"); } public static int defaultMaxRedirects() { - return getIntValue(ASYNC_CLIENT + "maxRedirects", 5); + return Integer.getInteger(ASYNC_CLIENT + "maxRedirects", 5); } public static boolean defaultCompressionEnabled() { - return getBooleanValue(ASYNC_CLIENT + "compressionEnabled",false); + return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); } public static String defaultUserAgent() { @@ -79,48 +74,48 @@ public static String defaultUserAgent() { } public static int defaultIoThreadMultiplier() { - return getIntValue(ASYNC_CLIENT + "ioThreadMultiplier", 2); + return Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2); } public static boolean defaultUseProxySelector() { - return getBooleanValue(ASYNC_CLIENT + "useProxySelector",false); + return Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); } public static boolean defaultUseProxyProperties() { - return getBooleanValue(ASYNC_CLIENT + "useProxyProperties",false); + return Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); } public static boolean defaultStrict302Handling() { - return getBooleanValue(ASYNC_CLIENT + "strict302Handling",false); + return Boolean.getBoolean(ASYNC_CLIENT + "strict302Handling"); } public static boolean defaultAllowPoolingConnection() { - return getBooleanValue(ASYNC_CLIENT + "allowPoolingConnection", true); + return getBoolean(ASYNC_CLIENT + "allowPoolingConnection", true); } public static boolean defaultUseRelativeURIsWithSSLProxies() { - return getBooleanValue(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); } // unused/broken, left there for compatibility, fixed in Netty 4 public static int defaultRequestCompressionLevel() { - return getIntValue(ASYNC_CLIENT + "requestCompressionLevel", -1); + return Integer.getInteger(ASYNC_CLIENT + "requestCompressionLevel", -1); } public static int defaultMaxRequestRetry() { - return getIntValue(ASYNC_CLIENT + "maxRequestRetry", 5); + return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); } public static boolean defaultAllowSslConnectionPool() { - return getBooleanValue(ASYNC_CLIENT + "allowSslConnectionPool", true); + return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); } public static boolean defaultUseRawUrl() { - return getBooleanValue(ASYNC_CLIENT + "useRawUrl",false); + return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrl"); } public static boolean defaultRemoveQueryParamOnRedirect() { - return getBooleanValue(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); + return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); } public static HostnameVerifier defaultHostnameVerifier() { @@ -128,15 +123,15 @@ public static HostnameVerifier defaultHostnameVerifier() { } public static boolean defaultSpdyEnabled() { - return getBooleanValue(ASYNC_CLIENT + "spdyEnabled",false); + return Boolean.getBoolean(ASYNC_CLIENT + "spdyEnabled"); } public static int defaultSpdyInitialWindowSize() { - return getIntValue(ASYNC_CLIENT + "spdyInitialWindowSize", 10 * 1024 * 1024); + return Integer.getInteger(ASYNC_CLIENT + "spdyInitialWindowSize", 10 * 1024 * 1024); } public static int defaultSpdyMaxConcurrentStreams() { - return getIntValue(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); + return Integer.getInteger(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100); } public static boolean defaultAcceptAnyCertificate() { diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java index 47b23bf767..a61d2d74d6 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java @@ -59,7 +59,7 @@ public static Class getAsyncImplClass(String propertyName) { return asyncHttpClientImplClass; } - public static Properties getAsyncImplProperties() { + private static Properties getAsyncImplProperties() { try { return AccessController.doPrivileged(new PrivilegedExceptionAction() { public Properties run() throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 054bb41fb9..3cad6cfd37 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -12,16 +12,11 @@ */ package org.asynchttpclient.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Map; -import java.util.Properties; public class MiscUtil { - public final static Logger logger = LoggerFactory.getLogger(MiscUtil.class); - private MiscUtil() { } @@ -45,69 +40,12 @@ public static boolean isNonEmpty(Map map) { return map != null && !map.isEmpty(); } - // The getBooleanValue() method replaces this and reads the property from - // properties file - // too. Plus has a better check for invalid boolean values. - /* - * public static boolean getBoolean(String systemPropName, boolean - * defaultValue) { String systemPropValue = - * System.getProperty(systemPropName); return systemPropValue != null ? - * systemPropValue.equalsIgnoreCase("true") : defaultValue; } - */ - - public static Integer getIntValue(String property, int defaultValue) { - // Read system property and if not null return that. - Integer value = Integer.getInteger(property); - if (value != null) - return value; - Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - if (asyncHttpClientConfigProperties != null) { - String valueString = asyncHttpClientConfigProperties.getProperty(property); - try { - // If property is present and is non null parse it. - if (valueString != null) - return Integer.parseInt(valueString); - } catch (NumberFormatException e) { - // If property couldn't be parsed log the error message and - // return default value. - logger.error("Property : " + property + " has value = " + valueString - + " which couldn't be parsed to an int value. Returning default value: " + defaultValue, e); - } - } - return defaultValue; - } - - private static boolean isValidBooleanValue(String value) { - return value != null && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)); + public static boolean getBoolean(String systemPropName, boolean defaultValue) { + String systemPropValue = System.getProperty(systemPropName); + return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; } - - public static Boolean getBooleanValue(String property, boolean defaultValue) { - - // get from System property first - String value = System.getProperty(property); - if (isValidBooleanValue(value)) - return Boolean.parseBoolean(value); - - // get from property file - Properties asyncHttpClientConfigProperties = AsyncImplHelper.getAsyncImplProperties(); - if (asyncHttpClientConfigProperties != null) { - value = asyncHttpClientConfigProperties.getProperty(property); - if (isValidBooleanValue(value)) - return Boolean.parseBoolean(value); - } - - // have to use the default value now - if (value != null) - logger.error("Property : " + property + " has value = " + value - + " which couldn't be parsed to an boolean value. Returning default value: " + defaultValue); - - return defaultValue; - } - - public static T withDefault(T value, T defaults) { return value != null? value : value; } - } diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java b/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java deleted file mode 100644 index 44818fb541..0000000000 --- a/api/src/test/java/org/asynchttpclient/AsyncHttpClientConfigBuilderTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.asynchttpclient; - -import org.testng.Assert; -import org.testng.annotations.Test; - -public class AsyncHttpClientConfigBuilderTest { - - @Test - public void testDefaultConfigValues() { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); - Assert.assertEquals(config.getConnectionTimeoutInMs(), 60000); - Assert.assertEquals(config.getRequestTimeoutInMs(), 60000); - Assert.assertEquals(config.getIdleConnectionTimeoutInMs(), 60000); - Assert.assertFalse(config.isCompressionEnabled()); - Assert.assertFalse(config.isRedirectEnabled()); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "connectionTimeoutInMs", "1000"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "requestTimeoutInMs", "500"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "compressionEnabled", "true"); - System.setProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "redirectsEnabled", "true"); - config = new AsyncHttpClientConfig.Builder().build(); - Assert.assertEquals(config.getConnectionTimeoutInMs(), 1000); - Assert.assertEquals(config.getRequestTimeoutInMs(), 500); - Assert.assertTrue(config.isCompressionEnabled()); - Assert.assertTrue(config.isRedirectEnabled()); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "connectionTimeoutInMs"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "requestTimeoutInMs"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "compressionEnabled"); - System.clearProperty(AsyncHttpClientConfig.ASYNC_CLIENT + "defaultRedirectsEnabled"); - } -} diff --git a/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java b/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java deleted file mode 100644 index e9f18af883..0000000000 --- a/api/src/test/java/org/asynchttpclient/AsyncImplHelperMock.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.asynchttpclient; - -import java.util.Properties; - -import mockit.Mock; -import mockit.MockUp; - -import org.asynchttpclient.util.AsyncImplHelper; - -public class AsyncImplHelperMock extends MockUp { - - private static Properties properties; - - public AsyncImplHelperMock(Properties properties) { - this.properties = properties; - } - - @Mock - public Properties getAsyncImplProperties() { - return properties; - } - -} diff --git a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java b/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java deleted file mode 100644 index 794090f43e..0000000000 --- a/api/src/test/java/org/asynchttpclient/util/MiscUtilTest.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.asynchttpclient.util; - -import java.util.Properties; - -import org.asynchttpclient.AsyncImplHelperMock; -import org.testng.Assert; -import org.testng.annotations.Test; - -public class MiscUtilTest { - private final Integer MY_SPECIAL_INT_VALUE = 10; - private final Integer MY_SPECIAL_SYSTEM_INT_VALUE = 100; - private final String MY_SPECIAL_INT_PROPERTY = "my.special.int.property"; - private final String MY_SPECIAL_BOOLEAN_PROPERTY = "my.special.boolean.property"; - private final Integer MY_SPECIAL_INT_DEFAULT_VALUE = -100; - - @Test - public void testGetIntegerValue() { - // Setup a AsyncImplHelperMock that returns a mock - // asynchttpclient.properties with a value - // set for 'my.special.int.property' property - Properties properties = new Properties(); - properties.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_VALUE.toString()); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getIntValue() method returns 10 - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); - // Set a system property that overrides the value in the - // asynchttpclient.properties - System.setProperty(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_SYSTEM_INT_VALUE.toString()); - // Assert 100 is returned, i.e. system property takes precedence over - // property in asynchttpclient.properties - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_SYSTEM_INT_VALUE); - // Clear the system property - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - // Assert that the value set in asynchttpclient.properties is returned - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that the value set in asynchttpclient.properties is returned - // even though corrupt system property is set. - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, -1), MY_SPECIAL_INT_VALUE); - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - } - - @Test - public void testGetBooleanValue() { - // Setup a AsyncImplHelperMock that returns a mock - // asynchttpclient.properties with a value - // set for 'my.special.int.property' property - Properties properties = new Properties(); - properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "true"); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getBooleanValue() method returns TRUE - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - // Set a system property that overrides the value in the - // asynchttpclient.properties - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "false"); - // Assert false is returned, i.e. system property takes precedence over - // property in asynchttpclient.properties - Assert.assertFalse(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Clear the system property - System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); - // Assert that the value set in asynchttpclient.properties is returned - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that the value set in asynchttpclient.properties is returned - // even though corrupt system property is set. - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - System.clearProperty(MY_SPECIAL_BOOLEAN_PROPERTY); - } - - @Test - public void testGetDefaultIntegerValue() { - - // Assert that the getIntValue() method returns the default value if - // Properties is not present - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); - // Setup up a mock of a asynchttpclient.properties that initially is - // empty - Properties properties = new Properties(); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getIntValue() method returns the default value if - // there is no - // property set in the asynchttpclient.properties - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); - // Now set a corrupt value in the asynchttpclient.properties - properties.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that the getIntValue() method returns the default value if - // there is a corrupt - // property set in the asynchttpclient.properties - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_INT_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and - // system property is corrupt the default value is - // returned - Assert.assertEquals(MiscUtil.getIntValue(MY_SPECIAL_INT_PROPERTY, MY_SPECIAL_INT_DEFAULT_VALUE), MY_SPECIAL_INT_DEFAULT_VALUE); - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - } - - @Test - public void testGetDefaultBooleanValue() { - // Assert that the getBooleanValue() method returns the default value if - // asynchttpclient.properties is not present - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Setup up a mock of a asynchttpclient.properties that initially is - // empty - Properties properties = new Properties(); - AsyncImplHelperMock asyncImplHelperMock = new AsyncImplHelperMock(properties); - - // Assert that the getBooleanValue() method returns the default value if - // there is no - // property set in the asynchttpclient.properties - Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - // Now set a corrupt value in the asynchttpclient.properties - properties.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that the getBooleanValue() method returns the default value if - // there is a corrupt - // property set in the asynchttpclient.properties - Assert.assertTrue(MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, true)); - // Set a corrupt system property - System.setProperty(MY_SPECIAL_BOOLEAN_PROPERTY, "corrupt property"); - // Assert that even though values set in asynchttpclient.properties and - // system property is corrupt the default value is - // returned - Assert.assertTrue(!MiscUtil.getBooleanValue(MY_SPECIAL_BOOLEAN_PROPERTY, false)); - System.clearProperty(MY_SPECIAL_INT_PROPERTY); - } -} diff --git a/pom.xml b/pom.xml index 4df2c85397..a4e54d8ded 100644 --- a/pom.xml +++ b/pom.xml @@ -514,17 +514,11 @@ test - com.e-movimento.tinytools - privilegedaccessor - ${privilegedaccessor.version} - test - - - com.googlecode.jmockit - jmockit - ${jmockit.version} - test - + com.e-movimento.tinytools + privilegedaccessor + ${privilegedaccessor.version} + test + http://oss.sonatype.org/content/repositories/snapshots @@ -539,7 +533,6 @@ 6.0.29 2.4 1.3 - 1.5 1.2.2 From ecb374a98cfa6299e5ae3020c0bba006463bf26d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 11:13:10 +0200 Subject: [PATCH 0113/2070] PR didn't compile... --- .../java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index edbc0c37eb..42bc30a4d8 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -140,6 +140,6 @@ public static int defaultSpdyMaxConcurrentStreams() { } public static boolean defaultAcceptAnyCertificate() { - return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false); + return getBooleanValue(ASYNC_CLIENT + "acceptAnyCertificate", false); } } From 713054c1359a0cb346fe966fc2ebd0999680f4f4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 11:36:39 +0200 Subject: [PATCH 0114/2070] Fix build after revert --- .../java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 88593ba310..3cb9ebddc7 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -135,6 +135,6 @@ public static int defaultSpdyMaxConcurrentStreams() { } public static boolean defaultAcceptAnyCertificate() { - return getBooleanValue(ASYNC_CLIENT + "acceptAnyCertificate", false); + return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false); } } From 7faf5eb2682789cae79d73fc8ba4d2f2e3c41cc4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 11:48:09 +0200 Subject: [PATCH 0115/2070] Move registry stuff to extra module --- extras/pom.xml | 1 + extras/registry/pom.xml | 30 +++++++++++++++++++ .../extra}/AsyncHttpClientFactory.java | 7 +++-- .../extra}/AsyncHttpClientImplException.java | 2 +- .../extra}/AsyncHttpClientRegistry.java | 5 ++-- .../extra}/AsyncHttpClientRegistryImpl.java | 4 +-- .../extra}/AsyncImplHelper.java | 4 +-- .../GrizzlyAsyncHttpClientFactoryTest.java | 5 ++-- .../NettyAsyncHttpClientFactoryTest.java | 5 ++-- .../AbstractAsyncHttpClientFactoryTest.java | 16 ++++++++-- .../extra}/AsyncHttpClientRegistryTest.java | 8 +++-- .../extra}/BadAsyncHttpClient.java | 12 +++++++- .../extra}/BadAsyncHttpClientException.java | 4 ++- .../extra}/BadAsyncHttpClientRegistry.java | 4 ++- .../extra}/TestAsyncHttpClientRegistry.java | 4 ++- 15 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 extras/registry/pom.xml rename {api/src/main/java/org/asynchttpclient => extras/registry/src/main/java/org/asynchttpclient/extra}/AsyncHttpClientFactory.java (96%) rename {api/src/main/java/org/asynchttpclient => extras/registry/src/main/java/org/asynchttpclient/extra}/AsyncHttpClientImplException.java (96%) rename {api/src/main/java/org/asynchttpclient => extras/registry/src/main/java/org/asynchttpclient/extra}/AsyncHttpClientRegistry.java (96%) rename {api/src/main/java/org/asynchttpclient => extras/registry/src/main/java/org/asynchttpclient/extra}/AsyncHttpClientRegistryImpl.java (98%) rename {api/src/main/java/org/asynchttpclient/util => extras/registry/src/main/java/org/asynchttpclient/extra}/AsyncImplHelper.java (97%) rename {providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly => extras/registry/src/main/java/org/asynchttpclient/extra}/GrizzlyAsyncHttpClientFactoryTest.java (87%) rename {providers/netty/src/test/java/org/asynchttpclient/providers/netty => extras/registry/src/main/java/org/asynchttpclient/extra}/NettyAsyncHttpClientFactoryTest.java (87%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/AbstractAsyncHttpClientFactoryTest.java (95%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/AsyncHttpClientRegistryTest.java (94%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/BadAsyncHttpClient.java (88%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/BadAsyncHttpClientException.java (89%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/BadAsyncHttpClientRegistry.java (89%) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extra}/TestAsyncHttpClientRegistry.java (88%) diff --git a/extras/pom.xml b/extras/pom.xml index 281689b29b..c220594e75 100644 --- a/extras/pom.xml +++ b/extras/pom.xml @@ -46,6 +46,7 @@ guava jdeferred + registry diff --git a/extras/registry/pom.xml b/extras/registry/pom.xml new file mode 100644 index 0000000000..66119acdb0 --- /dev/null +++ b/extras/registry/pom.xml @@ -0,0 +1,30 @@ + + + org.asynchttpclient + async-http-client-extras-parent + 2.0.0-SNAPSHOT + + 4.0.0 + async-http-client-extras-registry + Asynchronous Http Client Registry Extras + + The Async Http Client Registry Extras. + + + + + + org.asynchttpclient + async-http-client-netty-provider + ${project.version} + test + + + org.asynchttpclient + async-http-client-grizzly-provider + ${project.version} + test + + + \ No newline at end of file diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java similarity index 96% rename from api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java index 8135f60163..780a0af585 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientFactory.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java @@ -10,9 +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 org.asynchttpclient; +package org.asynchttpclient.extra; -import org.asynchttpclient.util.AsyncImplHelper; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.DefaultAsyncHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.java similarity index 96% rename from api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.java index 08e75e90fd..1862ea8c70 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientImplException.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.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 org.asynchttpclient; +package org.asynchttpclient.extra; @SuppressWarnings("serial") public class AsyncHttpClientImplException extends RuntimeException { diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java similarity index 96% rename from api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java index 5e05afa780..13ce83081e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistry.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java @@ -10,7 +10,9 @@ * "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 org.asynchttpclient; +package org.asynchttpclient.extra; + +import org.asynchttpclient.AsyncHttpClient; import java.util.Set; @@ -79,4 +81,3 @@ public interface AsyncHttpClientRegistry { void clearAllInstances(); } - diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java similarity index 98% rename from api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java index 61d8f3d38a..378f19290e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientRegistryImpl.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java @@ -10,9 +10,9 @@ * "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 org.asynchttpclient; +package org.asynchttpclient.extra; -import org.asynchttpclient.util.AsyncImplHelper; +import org.asynchttpclient.AsyncHttpClient; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java similarity index 97% rename from api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java index a61d2d74d6..5f341d3ae7 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncImplHelper.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java @@ -10,11 +10,9 @@ * "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 org.asynchttpclient.util; +package org.asynchttpclient.extra; import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientFactory; -import org.asynchttpclient.AsyncHttpClientImplException; import java.io.IOException; import java.io.InputStream; diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java b/extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java similarity index 87% rename from providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java index e201b05a9d..ed27eb1257 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java @@ -10,11 +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 org.asynchttpclient.providers.grizzly; +package org.asynchttpclient.extra; -import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.extra.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; import org.testng.annotations.Test; @Test diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java b/extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java similarity index 87% rename from providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java rename to extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java index dc2d152b0f..340b3befe2 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java @@ -10,11 +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 org.asynchttpclient.providers.netty; +package org.asynchttpclient.extra; -import org.asynchttpclient.AbstractAsyncHttpClientFactoryTest; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.extra.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProvider; import org.testng.annotations.Test; @Test diff --git a/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java similarity index 95% rename from api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java index 757c1c26d9..7ee6f94d36 100644 --- a/api/src/test/java/org/asynchttpclient/AbstractAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java @@ -10,11 +10,20 @@ * "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 org.asynchttpclient; - +package org.asynchttpclient.extra; + +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.DefaultAsyncHttpClient; +import org.asynchttpclient.Response; +import org.asynchttpclient.TestAsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig.Builder; import org.asynchttpclient.async.util.EchoHandler; import org.asynchttpclient.async.util.TestUtils; -import org.asynchttpclient.util.AsyncImplHelper; +import org.asynchttpclient.extra.AsyncHttpClientFactory; +import org.asynchttpclient.extra.AsyncHttpClientImplException; +import org.asynchttpclient.extra.AsyncImplHelper; import org.eclipse.jetty.server.Server; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -23,6 +32,7 @@ import org.testng.annotations.Test; import java.lang.reflect.InvocationTargetException; + import junit.extensions.PA; public abstract class AbstractAsyncHttpClientFactoryTest { diff --git a/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java similarity index 94% rename from api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java index 569c539308..c973b6d59e 100644 --- a/api/src/test/java/org/asynchttpclient/AsyncHttpClientRegistryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java @@ -10,9 +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 org.asynchttpclient; +package org.asynchttpclient.extra; -import org.asynchttpclient.util.AsyncImplHelper; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.extra.AsyncHttpClientFactory; +import org.asynchttpclient.extra.AsyncHttpClientImplException; +import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; +import org.asynchttpclient.extra.AsyncImplHelper; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java similarity index 88% rename from api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java index f8e72c9538..d9b0a5c3c1 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClient.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java @@ -10,7 +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 org.asynchttpclient; +package org.asynchttpclient.extra; + +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.BoundRequestBuilder; +import org.asynchttpclient.ListenableFuture; +import org.asynchttpclient.Request; +import org.asynchttpclient.Response; +import org.asynchttpclient.SignatureCalculator; import java.io.IOException; diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java similarity index 89% rename from api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java index af384e8623..318d59ddbf 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientException.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java @@ -10,7 +10,9 @@ * "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 org.asynchttpclient; +package org.asynchttpclient.extra; + +import org.asynchttpclient.extra.AsyncHttpClientImplException; @SuppressWarnings("serial") public class BadAsyncHttpClientException extends AsyncHttpClientImplException { diff --git a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java similarity index 89% rename from api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java index 9ed9b5de88..7aef111bd0 100644 --- a/api/src/test/java/org/asynchttpclient/BadAsyncHttpClientRegistry.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java @@ -10,7 +10,9 @@ * "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 org.asynchttpclient; +package org.asynchttpclient.extra; + +import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; public class BadAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java b/extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java similarity index 88% rename from api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java rename to extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java index 2f4ec9247e..84f052ddcb 100644 --- a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClientRegistry.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java @@ -10,7 +10,9 @@ * "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 org.asynchttpclient; +package org.asynchttpclient.extra; + +import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; public class TestAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { From e966f74cd5b0451e96767dcbad082a8d8d78ec57 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 12:02:16 +0200 Subject: [PATCH 0116/2070] Move to proper per extras packages --- .../guava}/ListenableFutureAdapter.java | 2 +- .../guava}/RateLimitedThrottleRequestFilter.java | 4 +++- .../jdeferred}/AsyncHttpDeferredObject.java | 2 +- .../jdeferred}/ContentWriteProgress.java | 2 +- .../{extra => extras/jdeferred}/HttpProgress.java | 2 +- .../jdeferred}/HttpResponseBodyPartProgress.java | 2 +- .../java/org/asynchttpclient/extra/AsyncHttpTest.java | 2 ++ .../registry}/AsyncHttpClientFactory.java | 2 +- .../registry}/AsyncHttpClientImplException.java | 2 +- .../registry}/AsyncHttpClientRegistry.java | 2 +- .../registry}/AsyncHttpClientRegistryImpl.java | 2 +- .../{extra => extras/registry}/AsyncImplHelper.java | 2 +- .../registry}/AbstractAsyncHttpClientFactoryTest.java | 9 ++++----- .../registry}/AsyncHttpClientRegistryTest.java | 10 +++++----- .../{extra => extras/registry}/BadAsyncHttpClient.java | 2 +- .../registry}/BadAsyncHttpClientException.java | 4 ++-- .../registry}/BadAsyncHttpClientRegistry.java | 4 ++-- .../registry}/GrizzlyAsyncHttpClientFactoryTest.java | 4 ++-- .../registry}/NettyAsyncHttpClientFactoryTest.java | 4 ++-- .../registry}/TestAsyncHttpClientRegistry.java | 4 ++-- 20 files changed, 35 insertions(+), 32 deletions(-) rename extras/guava/src/main/java/org/asynchttpclient/{extra => extras/guava}/ListenableFutureAdapter.java (98%) rename extras/guava/src/main/java/org/asynchttpclient/{extra => extras/guava}/RateLimitedThrottleRequestFilter.java (96%) rename extras/jdeferred/src/main/java/org/asynchttpclient/{extra => extras/jdeferred}/AsyncHttpDeferredObject.java (98%) rename extras/jdeferred/src/main/java/org/asynchttpclient/{extra => extras/jdeferred}/ContentWriteProgress.java (96%) rename extras/jdeferred/src/main/java/org/asynchttpclient/{extra => extras/jdeferred}/HttpProgress.java (93%) rename extras/jdeferred/src/main/java/org/asynchttpclient/{extra => extras/jdeferred}/HttpResponseBodyPartProgress.java (95%) rename extras/registry/src/main/java/org/asynchttpclient/{extra => extras/registry}/AsyncHttpClientFactory.java (99%) rename extras/registry/src/main/java/org/asynchttpclient/{extra => extras/registry}/AsyncHttpClientImplException.java (95%) rename extras/registry/src/main/java/org/asynchttpclient/{extra => extras/registry}/AsyncHttpClientRegistry.java (98%) rename extras/registry/src/main/java/org/asynchttpclient/{extra => extras/registry}/AsyncHttpClientRegistryImpl.java (98%) rename extras/registry/src/main/java/org/asynchttpclient/{extra => extras/registry}/AsyncImplHelper.java (99%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/AbstractAsyncHttpClientFactoryTest.java (97%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/AsyncHttpClientRegistryTest.java (94%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/BadAsyncHttpClient.java (98%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/BadAsyncHttpClientException.java (88%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/BadAsyncHttpClientRegistry.java (88%) rename extras/registry/src/{main/java/org/asynchttpclient/extra => test/java/org/asynchttpclient/extras/registry}/GrizzlyAsyncHttpClientFactoryTest.java (91%) rename extras/registry/src/{main/java/org/asynchttpclient/extra => test/java/org/asynchttpclient/extras/registry}/NettyAsyncHttpClientFactoryTest.java (91%) rename extras/registry/src/test/java/org/asynchttpclient/{extra => extras/registry}/TestAsyncHttpClientRegistry.java (86%) diff --git a/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java b/extras/guava/src/main/java/org/asynchttpclient/extras/guava/ListenableFutureAdapter.java similarity index 98% rename from extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java rename to extras/guava/src/main/java/org/asynchttpclient/extras/guava/ListenableFutureAdapter.java index 6ac40b92c6..9c51d29b68 100644 --- a/extras/guava/src/main/java/org/asynchttpclient/extra/ListenableFutureAdapter.java +++ b/extras/guava/src/main/java/org/asynchttpclient/extras/guava/ListenableFutureAdapter.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.guava; import org.asynchttpclient.ListenableFuture; diff --git a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java b/extras/guava/src/main/java/org/asynchttpclient/extras/guava/RateLimitedThrottleRequestFilter.java similarity index 96% rename from extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java rename to extras/guava/src/main/java/org/asynchttpclient/extras/guava/RateLimitedThrottleRequestFilter.java index d6ddb69a68..dc07928d43 100644 --- a/extras/guava/src/main/java/org/asynchttpclient/extra/RateLimitedThrottleRequestFilter.java +++ b/extras/guava/src/main/java/org/asynchttpclient/extras/guava/RateLimitedThrottleRequestFilter.java @@ -1,5 +1,7 @@ -package org.asynchttpclient.extra; +package org.asynchttpclient.extras.guava; +import org.asynchttpclient.extra.AsyncHandlerWrapper; +import org.asynchttpclient.extra.ThrottleRequestFilter; import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.RequestFilter; diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/AsyncHttpDeferredObject.java similarity index 98% rename from extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java rename to extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/AsyncHttpDeferredObject.java index 7be6007aa0..9f50dc71cc 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/AsyncHttpDeferredObject.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/AsyncHttpDeferredObject.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.extra; +package org.asynchttpclient.extras.jdeferred; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/ContentWriteProgress.java similarity index 96% rename from extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java rename to extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/ContentWriteProgress.java index 0f3b5b5ddc..b07a76d3f7 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/ContentWriteProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/ContentWriteProgress.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.extra; +package org.asynchttpclient.extras.jdeferred; public class ContentWriteProgress implements HttpProgress { private final long amount; diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpProgress.java similarity index 93% rename from extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java rename to extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpProgress.java index 19a3e22796..8ff4788564 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpProgress.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.extra; +package org.asynchttpclient.extras.jdeferred; public interface HttpProgress { } diff --git a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpResponseBodyPartProgress.java similarity index 95% rename from extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java rename to extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpResponseBodyPartProgress.java index 362d1fb1a8..7137c5469b 100644 --- a/extras/jdeferred/src/main/java/org/asynchttpclient/extra/HttpResponseBodyPartProgress.java +++ b/extras/jdeferred/src/main/java/org/asynchttpclient/extras/jdeferred/HttpResponseBodyPartProgress.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.extra; +package org.asynchttpclient.extras.jdeferred; import org.asynchttpclient.HttpResponseBodyPart; diff --git a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java index 0d5eeb837b..cb58470173 100644 --- a/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java +++ b/extras/jdeferred/src/test/java/org/asynchttpclient/extra/AsyncHttpTest.java @@ -21,6 +21,8 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.DefaultAsyncHttpClient; import org.asynchttpclient.Response; +import org.asynchttpclient.extras.jdeferred.AsyncHttpDeferredObject; +import org.asynchttpclient.extras.jdeferred.HttpProgress; import org.jdeferred.DoneCallback; import org.jdeferred.ProgressCallback; import org.jdeferred.Promise; diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientFactory.java similarity index 99% rename from extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java rename to extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientFactory.java index 780a0af585..90457a924f 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientFactory.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientFactory.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.java b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientImplException.java similarity index 95% rename from extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.java rename to extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientImplException.java index 1862ea8c70..f59bf0698c 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientImplException.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientImplException.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; @SuppressWarnings("serial") public class AsyncHttpClientImplException extends RuntimeException { diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistry.java similarity index 98% rename from extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java rename to extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistry.java index 13ce83081e..ca63009ce7 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistry.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistry.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryImpl.java similarity index 98% rename from extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java rename to extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryImpl.java index 378f19290e..0c13c2e585 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncHttpClientRegistryImpl.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryImpl.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncImplHelper.java similarity index 99% rename from extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java rename to extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncImplHelper.java index 5f341d3ae7..0e827c0114 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/AsyncImplHelper.java +++ b/extras/registry/src/main/java/org/asynchttpclient/extras/registry/AsyncImplHelper.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java similarity index 97% rename from extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java index 7ee6f94d36..4561a751ee 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/AbstractAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; @@ -18,12 +18,11 @@ import org.asynchttpclient.DefaultAsyncHttpClient; import org.asynchttpclient.Response; import org.asynchttpclient.TestAsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig.Builder; import org.asynchttpclient.async.util.EchoHandler; import org.asynchttpclient.async.util.TestUtils; -import org.asynchttpclient.extra.AsyncHttpClientFactory; -import org.asynchttpclient.extra.AsyncHttpClientImplException; -import org.asynchttpclient.extra.AsyncImplHelper; +import org.asynchttpclient.extras.registry.AsyncHttpClientFactory; +import org.asynchttpclient.extras.registry.AsyncHttpClientImplException; +import org.asynchttpclient.extras.registry.AsyncImplHelper; import org.eclipse.jetty.server.Server; import org.testng.Assert; import org.testng.annotations.AfterClass; diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java similarity index 94% rename from extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java index c973b6d59e..ffd8afad0f 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/AsyncHttpClientRegistryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.extra.AsyncHttpClientFactory; -import org.asynchttpclient.extra.AsyncHttpClientImplException; -import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; -import org.asynchttpclient.extra.AsyncImplHelper; +import org.asynchttpclient.extras.registry.AsyncHttpClientFactory; +import org.asynchttpclient.extras.registry.AsyncHttpClientImplException; +import org.asynchttpclient.extras.registry.AsyncHttpClientRegistryImpl; +import org.asynchttpclient.extras.registry.AsyncImplHelper; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClient.java similarity index 98% rename from extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClient.java index d9b0a5c3c1..84343ec0d4 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClient.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClient.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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClient; diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientException.java similarity index 88% rename from extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientException.java index 318d59ddbf..1aca098e89 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientException.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientException.java @@ -10,9 +10,9 @@ * "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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; -import org.asynchttpclient.extra.AsyncHttpClientImplException; +import org.asynchttpclient.extras.registry.AsyncHttpClientImplException; @SuppressWarnings("serial") public class BadAsyncHttpClientException extends AsyncHttpClientImplException { diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientRegistry.java similarity index 88% rename from extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientRegistry.java index 7aef111bd0..b3d853de3f 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/BadAsyncHttpClientRegistry.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/BadAsyncHttpClientRegistry.java @@ -10,9 +10,9 @@ * "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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; -import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; +import org.asynchttpclient.extras.registry.AsyncHttpClientRegistryImpl; public class BadAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/GrizzlyAsyncHttpClientFactoryTest.java similarity index 91% rename from extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/GrizzlyAsyncHttpClientFactoryTest.java index ed27eb1257..cfa9c9d4bd 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/GrizzlyAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/GrizzlyAsyncHttpClientFactoryTest.java @@ -10,11 +10,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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; -import org.asynchttpclient.extra.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.extras.registry.AbstractAsyncHttpClientFactoryTest; import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; import org.testng.annotations.Test; diff --git a/extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/NettyAsyncHttpClientFactoryTest.java similarity index 91% rename from extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/NettyAsyncHttpClientFactoryTest.java index 340b3befe2..a5cc1fa028 100644 --- a/extras/registry/src/main/java/org/asynchttpclient/extra/NettyAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/NettyAsyncHttpClientFactoryTest.java @@ -10,11 +10,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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; -import org.asynchttpclient.extra.AbstractAsyncHttpClientFactoryTest; +import org.asynchttpclient.extras.registry.AbstractAsyncHttpClientFactoryTest; import org.asynchttpclient.providers.netty.NettyAsyncHttpProvider; import org.testng.annotations.Test; diff --git a/extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClientRegistry.java similarity index 86% rename from extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClientRegistry.java index 84f052ddcb..b9410737d5 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extra/TestAsyncHttpClientRegistry.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClientRegistry.java @@ -10,9 +10,9 @@ * "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 org.asynchttpclient.extra; +package org.asynchttpclient.extras.registry; -import org.asynchttpclient.extra.AsyncHttpClientRegistryImpl; +import org.asynchttpclient.extras.registry.AsyncHttpClientRegistryImpl; public class TestAsyncHttpClientRegistry extends AsyncHttpClientRegistryImpl { From de6030eeaa939dfb99a4715312a3eba8b71c6c3e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 12:54:52 +0200 Subject: [PATCH 0117/2070] Minor clean up --- .../org/asynchttpclient/util/AsyncHttpProviderUtils.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 6a7bb09cc4..1f614a507d 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -65,13 +65,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 85bb8150db972e3b3d9f965e672df0afd5bc8fda Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 13:47:07 +0200 Subject: [PATCH 0118/2070] Drop Proxy.getURI, close #586 --- .../DefaultConnectionPoolStrategy.java | 2 +- .../main/java/org/asynchttpclient/ProxyServer.java | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java index 2ae901ea80..55d1a1eff8 100644 --- a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java +++ b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java @@ -26,6 +26,6 @@ public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { @Override public String getKey(URI uri, ProxyServer proxyServer) { String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); - return proxyServer != null ? AsyncHttpProviderUtils.getBaseUrl(proxyServer.getURI()) + serverPart : serverPart; + return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } } diff --git a/api/src/main/java/org/asynchttpclient/ProxyServer.java b/api/src/main/java/org/asynchttpclient/ProxyServer.java index 171c6f6238..3c6a5ff429 100644 --- a/api/src/main/java/org/asynchttpclient/ProxyServer.java +++ b/api/src/main/java/org/asynchttpclient/ProxyServer.java @@ -16,10 +16,8 @@ */ package org.asynchttpclient; -import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.util.StandardCharsets; -import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -55,7 +53,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 = StandardCharsets.UTF_8.name(); private Charset charset = StandardCharsets.UTF_8; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); @@ -66,7 +64,7 @@ public ProxyServer(final Protocol protocol, final String host, final int port, S this.port = port; this.principal = principal; this.password = password; - this.uri = AsyncHttpProviderUtils.createNonEmptyPathURI(toString()); + url = protocol + "://" + host + ":" + port; } public ProxyServer(final String host, final int port, String principal, String password) { @@ -119,8 +117,8 @@ public Charset getCharset() { return charset; } - public URI getURI() { - return uri; + public String getUrl() { + return url; } public ProxyServer addNonProxyHost(String uri) { @@ -148,6 +146,6 @@ public String getNtlmDomain() { @Override public String toString() { - return protocol + "://" + host + ":" + port; + return url; } } From 32c74a4407d45dfac4bdd9b13769c99abc8bc550 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 00:24:12 +0200 Subject: [PATCH 0119/2070] Port on master new Request API, close #588 --- .../AsyncHttpClientConfig.java | 44 +- .../AsyncHttpClientConfigBean.java | 12 +- .../AsyncHttpClientConfigDefaults.java | 8 +- .../asynchttpclient/BoundRequestBuilder.java | 29 +- .../ConnectionPoolKeyStrategy.java | 4 +- .../DefaultAsyncHttpClient.java | 4 +- .../DefaultConnectionPoolStrategy.java | 5 +- .../org/asynchttpclient/FluentStringsMap.java | 40 +- .../asynchttpclient/HttpResponseStatus.java | 13 +- .../main/java/org/asynchttpclient/Param.java | 62 +++ .../asynchttpclient/ProxyServerSelector.java | 6 +- .../java/org/asynchttpclient/Request.java | 63 +-- .../org/asynchttpclient/RequestBuilder.java | 51 ++- .../asynchttpclient/RequestBuilderBase.java | 410 ++++++++---------- .../java/org/asynchttpclient/Response.java | 10 +- .../asynchttpclient/SignatureCalculator.java | 3 +- .../SimpleAsyncHttpClient.java | 30 +- .../oauth/OAuthSignatureCalculator.java | 72 ++- .../providers/ResponseBase.java | 4 +- .../resumable/ResumableAsyncHandler.java | 2 +- .../asynchttpclient/uri/UriComponents.java | 182 ++++++++ .../uri/UriComponentsParser.java | 340 +++++++++++++++ .../util/AsyncHttpProviderUtils.java | 95 +--- .../org/asynchttpclient/util/ProxyUtils.java | 56 +-- .../asynchttpclient/util/QueryComputer.java | 140 ++++++ .../util/StringCharSequence.java | 54 +++ .../asynchttpclient/util/UTF8UrlDecoder.java | 70 +++ .../asynchttpclient/util/UTF8UrlEncoder.java | 42 +- .../webdav/WebDavCompletionHandlerBase.java | 25 +- .../webdav/WebDavResponse.java | 15 +- .../async/AsyncProvidersBasicTest.java | 13 +- .../async/AsyncStreamHandlerTest.java | 8 +- .../async/ParamEncodingTest.java | 2 +- .../async/PerRequestRelative302Test.java | 26 +- .../async/PostRedirectGetTest.java | 4 +- .../asynchttpclient/async/PostWithQSTest.java | 8 +- .../async/QueryParametersTest.java | 17 +- .../async/Relative302Test.java | 27 +- .../async/RequestBuilderTest.java | 23 +- .../oauth/TestSignatureCalculator.java | 14 +- .../util/AsyncHttpProviderUtilsTest.java | 47 -- .../providers/grizzly/ConnectionManager.java | 16 +- .../providers/grizzly/EventHandler.java | 19 +- .../grizzly/GrizzlyResponseStatus.java | 4 +- .../providers/grizzly/HttpTxContext.java | 2 +- .../grizzly/ProxyAwareConnectorHandler.java | 7 +- .../providers/grizzly/Utils.java | 4 +- .../bodyhandler/ParamsBodyHandler.java | 29 +- .../filters/AsyncHttpClientFilter.java | 40 +- .../grizzly/filters/TunnelFilter.java | 10 +- .../filters/events/TunnelRequestEvent.java | 9 +- .../ProxyAuthorizationHandler.java | 2 +- .../statushandler/RedirectHandler.java | 12 +- .../GrizzlyNoTransferEncodingTest.java | 2 +- providers/netty/pom.xml | 2 +- .../providers/netty/channel/Channels.java | 6 +- .../netty/future/NettyResponseFuture.java | 10 +- .../providers/netty/handler/HttpProtocol.java | 35 +- .../providers/netty/handler/Protocol.java | 28 +- .../netty/handler/WebSocketProtocol.java | 2 +- .../netty/request/NettyRequestFactory.java | 70 ++- .../netty/request/NettyRequestSender.java | 26 +- .../netty/response/ResponseHeaders.java | 13 +- .../netty/response/ResponseStatus.java | 4 +- .../providers/netty/util/HttpUtil.java | 5 +- .../providers/netty/NettyFilterTest.java | 2 + .../netty/RetryNonBlockingIssue.java | 6 +- 67 files changed, 1539 insertions(+), 906 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/Param.java create mode 100644 api/src/main/java/org/asynchttpclient/uri/UriComponents.java create mode 100644 api/src/main/java/org/asynchttpclient/uri/UriComponentsParser.java create mode 100644 api/src/main/java/org/asynchttpclient/util/QueryComputer.java create mode 100644 api/src/main/java/org/asynchttpclient/util/StringCharSequence.java create mode 100644 api/src/main/java/org/asynchttpclient/util/UTF8UrlDecoder.java delete mode 100644 api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 444ceda349..65fac8d2be 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -85,7 +85,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; @@ -101,7 +101,7 @@ public class AsyncHttpClientConfig { protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; - protected boolean useRawUrl; + protected boolean disableUrlEncodingForBoundRequests; protected boolean removeQueryParamOnRedirect; protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; @@ -125,7 +125,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // int idleConnectionTimeoutInMs, // int requestTimeoutInMs, // int connectionMaxLifeTimeInMs, // - boolean redirectEnabled, // + boolean followRedirect, // int maxRedirects, // boolean compressionEnabled, // String userAgent, // @@ -143,7 +143,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // int requestCompressionLevel, // int maxRequestRetry, // boolean allowSslConnectionCaching, // - boolean useRawUrl, // + boolean disableUrlEncodingForBoundRequests, // boolean removeQueryParamOnRedirect, // HostnameVerifier hostnameVerifier, // int ioThreadMultiplier, // @@ -163,7 +163,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; @@ -184,7 +184,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; this.applicationThreadPool = applicationThreadPool; this.proxyServerSelector = proxyServerSelector; - this.useRawUrl = useRawUrl; + this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; this.spdyEnabled = spdyEnabled; this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; @@ -262,8 +262,8 @@ public int getRequestTimeoutInMs() { * * @return true if enabled. */ - public boolean isRedirectEnabled() { - return redirectEnabled; + public boolean isFollowRedirect() { + return followRedirect; } /** @@ -422,10 +422,10 @@ public boolean isSslConnectionPoolEnabled() { } /** - * @return the useRawUrl + * @return the disableUrlEncodingForBoundRequests */ - public boolean isUseRawUrl() { - return useRawUrl; + public boolean isDisableUrlEncodingForBoundRequests() { + return disableUrlEncodingForBoundRequests; } /** @@ -552,7 +552,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 maxRedirects = defaultMaxRedirects(); private boolean compressionEnabled = defaultCompressionEnabled(); private String userAgent = defaultUserAgent(); @@ -564,7 +564,7 @@ public static class Builder { private int maxRequestRetry = defaultMaxRequestRetry(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); - private boolean useRawUrl = defaultUseRawUrl(); + private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); @@ -676,8 +676,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 setFollowRedirects(boolean followRedirect) { + this.followRedirect = followRedirect; return this; } @@ -933,11 +933,11 @@ public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { * Allows use unescaped URLs in requests * useful for retrieving data from broken sites * - * @param useRawUrl + * @param disableUrlEncodingForBoundRequests * @return this */ - public Builder setUseRawUrl(boolean useRawUrl) { - this.useRawUrl = useRawUrl; + public Builder setDisableUrlEncodingForBoundRequests(boolean disableUrlEncodingForBoundRequests) { + this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; return this; } @@ -1111,7 +1111,7 @@ public Builder(AsyncHttpClientConfig prototype) { requestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); userAgent = prototype.getUserAgent(); - redirectEnabled = prototype.isRedirectEnabled(); + followRedirect = prototype.isFollowRedirect(); compressionEnabled = prototype.isCompressionEnabled(); applicationThreadPool = prototype.executorService(); @@ -1124,7 +1124,7 @@ public Builder(AsyncHttpClientConfig prototype) { ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); requestCompressionLevel = prototype.getRequestCompressionLevel(); - useRawUrl = prototype.isUseRawUrl(); + disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); allowSslConnectionPool = prototype.getAllowPoolingConnection(); @@ -1172,7 +1172,7 @@ public Thread newThread(Runnable r) { idleConnectionTimeoutInMs, // requestTimeoutInMs, // maxConnectionLifeTimeInMs, // - redirectEnabled, // + followRedirect, // maxRedirects, // compressionEnabled, // userAgent, // @@ -1190,7 +1190,7 @@ public Thread newThread(Runnable r) { requestCompressionLevel, // maxRequestRetry, // allowSslConnectionPool, // - useRawUrl, // + disableUrlEncodingForBoundRequests, // removeQueryParamOnRedirect, // hostnameVerifier, // ioThreadMultiplier, // diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 463d0c2c37..6c677b075e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -53,7 +53,7 @@ void configureDefaults() { idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); requestTimeoutInMs = defaultRequestTimeoutInMs(); maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); - redirectEnabled = defaultRedirectEnabled(); + followRedirect = defaultFollowRedirect(); maxRedirects = defaultMaxRedirects(); compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); @@ -63,7 +63,7 @@ void configureDefaults() { maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); - useRawUrl = defaultUseRawUrl(); + disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); @@ -123,8 +123,8 @@ public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) { return this; } - public AsyncHttpClientConfigBean setRedirectEnabled(boolean redirectEnabled) { - this.redirectEnabled = redirectEnabled; + public AsyncHttpClientConfigBean setFollowRedirect(boolean followRedirect) { + this.followRedirect = followRedirect; return this; } @@ -216,8 +216,8 @@ public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConne return this; } - public AsyncHttpClientConfigBean setUseRawUrl(boolean useRawUrl) { - this.useRawUrl = useRawUrl; + public AsyncHttpClientConfigBean setDisableUrlEncodingForBoundRequests(boolean disableUrlEncodingForBoundRequests) { + this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; return this; } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 3cb9ebddc7..4de9e2fcb6 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -57,8 +57,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() { @@ -110,8 +110,8 @@ public static boolean defaultAllowSslConnectionPool() { return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); } - public static boolean defaultUseRawUrl() { - return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrl"); + public static boolean defaultDisableUrlEncodingForBoundRequests() { + return Boolean.getBoolean(ASYNC_CLIENT + "disableUrlEncodingForBoundRequests"); } public static boolean defaultRemoveQueryParamOnRedirect() { diff --git a/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java index b42f2e2eae..638450a202 100644 --- a/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java +++ b/api/src/main/java/org/asynchttpclient/BoundRequestBuilder.java @@ -18,14 +18,15 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.List; import java.util.Map; public class BoundRequestBuilder extends RequestBuilderBase { private final AsyncHttpClient client; - public BoundRequestBuilder(AsyncHttpClient client, String reqType, boolean useRawUrl) { - super(BoundRequestBuilder.class, reqType, useRawUrl); + public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding) { + super(BoundRequestBuilder.class, method, isDisableUrlEncoding); this.client = client; } @@ -42,9 +43,10 @@ public ListenableFuture execute() throws IOException { return client.executeRequest(build(), new AsyncCompletionHandlerBase()); } - // 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 + // 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 @Override public BoundRequestBuilder addBodyPart(Part part) { @@ -62,13 +64,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 @@ -107,13 +109,13 @@ public BoundRequestBuilder setHeaders(Map> headers) { } @Override - public BoundRequestBuilder setParameters(Map> parameters) { - return super.setParameters(parameters); + public BoundRequestBuilder setFormParams(Map> params) { + return super.setFormParams(params); } @Override - public BoundRequestBuilder setParameters(FluentStringsMap parameters) { - return super.setParameters(parameters); + public BoundRequestBuilder setFormParams(List params) { + return super.setFormParams(params); } @Override @@ -126,7 +128,6 @@ public BoundRequestBuilder setVirtualHost(String virtualHost) { return super.setVirtualHost(virtualHost); } - @Override public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureCalculator) { return super.setSignatureCalculator(signatureCalculator); } diff --git a/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java b/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java index adf626f307..704ed78cb1 100644 --- a/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java +++ b/api/src/main/java/org/asynchttpclient/ConnectionPoolKeyStrategy.java @@ -15,9 +15,9 @@ */ package org.asynchttpclient; -import java.net.URI; +import org.asynchttpclient.uri.UriComponents; public interface ConnectionPoolKeyStrategy { - String getKey(URI uri, ProxyServer proxy); + String getKey(UriComponents uri, ProxyServer proxy); } diff --git a/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java index e6ba817ea2..63536a37c4 100644 --- a/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java @@ -311,8 +311,8 @@ private static AsyncHttpProvider loadDefaultProvider(String[] providerClassNames throw new IllegalStateException("No providers found on the classpath"); } - protected BoundRequestBuilder requestBuilder(String reqType, String url) { - return new BoundRequestBuilder(this, reqType, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); + protected BoundRequestBuilder requestBuilder(String method, String url) { + return new BoundRequestBuilder(this, method, config.isDisableUrlEncodingForBoundRequests()).setUrl(url).setSignatureCalculator(signatureCalculator); } protected BoundRequestBuilder requestBuilder(Request prototype) { diff --git a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java index 55d1a1eff8..6b2c9ae5b7 100644 --- a/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java +++ b/api/src/main/java/org/asynchttpclient/DefaultConnectionPoolStrategy.java @@ -15,16 +15,15 @@ */ package org.asynchttpclient; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; -import java.net.URI; - public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { INSTANCE; @Override - public String getKey(URI uri, ProxyServer proxyServer) { + public String getKey(UriComponents uri, ProxyServer proxyServer) { String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } diff --git a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java index 34cc5ff237..b295b7a1be 100644 --- a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java @@ -195,7 +195,7 @@ public FluentStringsMap replaceAll(Map put(String key, List value) { if (key == null) { throw new NullPointerException("Null keys are not allowed"); @@ -210,7 +210,7 @@ public List put(String key, List value) { /** * {@inheritDoc} */ - @Override + /* @Override */ public void putAll(Map> values) { replaceAll(values); } @@ -259,7 +259,7 @@ public FluentStringsMap deleteAll(Collection keys) { /** * {@inheritDoc} */ - @Override + /* @Override */ public List remove(Object key) { if (key == null) { return null; @@ -274,7 +274,7 @@ public List remove(Object key) { /** * {@inheritDoc} */ - @Override + /* @Override */ public void clear() { values.clear(); } @@ -282,7 +282,7 @@ public void clear() { /** * {@inheritDoc} */ - @Override + /* @Override */ public Iterator>> iterator() { return Collections.unmodifiableSet(values.entrySet()).iterator(); } @@ -290,7 +290,7 @@ public Iterator>> iterator() { /** * {@inheritDoc} */ - @Override + /* @Override */ public Set keySet() { return Collections.unmodifiableSet(values.keySet()); } @@ -298,7 +298,7 @@ public Set keySet() { /** * {@inheritDoc} */ - @Override + /* @Override */ public Set>> entrySet() { return values.entrySet(); } @@ -306,7 +306,7 @@ public Set>> entrySet() { /** * {@inheritDoc} */ - @Override + /* @Override */ public int size() { return values.size(); } @@ -314,7 +314,7 @@ public int size() { /** * {@inheritDoc} */ - @Override + /* @Override */ public boolean isEmpty() { return values.isEmpty(); } @@ -322,7 +322,7 @@ public boolean isEmpty() { /** * {@inheritDoc} */ - @Override + /* @Override */ public boolean containsKey(Object key) { return key == null ? false : values.containsKey(key.toString()); } @@ -330,7 +330,7 @@ public boolean containsKey(Object key) { /** * {@inheritDoc} */ - @Override + /* @Override */ public boolean containsValue(Object value) { return values.containsValue(value); } @@ -383,7 +383,7 @@ public String getJoinedValue(String key, String delimiter) { /** * {@inheritDoc} */ - @Override + /* @Override */ public List get(Object key) { if (key == null) { return null; @@ -395,11 +395,25 @@ public List get(Object key) { /** * {@inheritDoc} */ - @Override + /* @Override */ 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/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java b/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java index d57a005441..ecf18cd980 100644 --- a/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java +++ b/api/src/main/java/org/asynchttpclient/HttpResponseStatus.java @@ -16,28 +16,29 @@ */ package org.asynchttpclient; -import java.net.URI; import java.util.List; +import org.asynchttpclient.uri.UriComponents; + /** * A class that represent the HTTP response' status line (code + text) */ public abstract class HttpResponseStatus { - private final URI uri; + private final UriComponents uri; protected final AsyncHttpClientConfig config; - public HttpResponseStatus(URI uri, AsyncHttpClientConfig config) { + public HttpResponseStatus(UriComponents uri, AsyncHttpClientConfig config) { this.uri = uri; this.config = config; } /** - * Return the request {@link URI} + * Return the request {@link UriComponents} * - * @return the request {@link URI} + * @return the request {@link UriComponents} */ - public final URI getUri() { + public final UriComponents getUri() { return uri; } diff --git a/api/src/main/java/org/asynchttpclient/Param.java b/api/src/main/java/org/asynchttpclient/Param.java new file mode 100644 index 0000000000..788f66c425 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient; + +/** + * 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/api/src/main/java/org/asynchttpclient/ProxyServerSelector.java b/api/src/main/java/org/asynchttpclient/ProxyServerSelector.java index b883b1fcf9..84862331f1 100644 --- a/api/src/main/java/org/asynchttpclient/ProxyServerSelector.java +++ b/api/src/main/java/org/asynchttpclient/ProxyServerSelector.java @@ -1,6 +1,6 @@ package org.asynchttpclient; -import java.net.URI; +import org.asynchttpclient.uri.UriComponents; /** * Selector for a proxy server @@ -13,14 +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() { @Override - public ProxyServer select(URI uri) { + public ProxyServer select(UriComponents uri) { return null; } }; diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index a54b96f32f..b182b2caf7 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -18,11 +18,11 @@ import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.uri.UriComponents; import java.io.File; import java.io.InputStream; import java.net.InetAddress; -import java.net.URI; import java.util.Collection; import java.util.List; @@ -53,11 +53,7 @@ public interface Request { */ String getUrl(); - URI getOriginalURI(); - - URI getURI(); - - URI getRawURI(); + UriComponents getURI(); /** * Return the InetAddress to override @@ -68,13 +64,6 @@ public interface Request { InetAddress getLocalAddress(); - /** - * Return the undecoded url - * - * @return the undecoded url - */ - String getRawUrl(); - /** * Return the current set of Headers. * @@ -82,14 +71,6 @@ public interface Request { */ FluentCaseInsensitiveStringsMap getHeaders(); - /** - * @return return true if request headers have been added, - * otherwise, returns false. - * - * @since 2.0 - */ - boolean hasHeaders(); - /** * Return Coookie. * @@ -126,18 +107,18 @@ public interface Request { BodyGenerator getBodyGenerator(); /** - * Return the current size of the content-length header based on the body's size. + * Return the current size of the content-lenght header based on the body's size. * - * @return the current size of the content-length header based on the body's size. + * @return the current size of the content-lenght header based on the body's size. */ long getContentLength(); /** - * Return the current parameters. + * Return the current form parameters. * * @return a {@link FluentStringsMap} of parameters. */ - FluentStringsMap getParams(); + List getFormParams(); /** * Return the current {@link Part} @@ -158,7 +139,7 @@ public interface Request { * * @return {@link FluentStringsMap} of query string */ - FluentStringsMap getQueryParams(); + List getQueryParams(); /** * Return the {@link ProxyServer} @@ -182,23 +163,16 @@ public interface Request { 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(); + Boolean getFollowRedirect(); /** - * - * @return true> if request's redirectEnabled setting - * should be used in place of client's - */ - boolean isRedirectOverrideSet(); - - /** - * Return the request time out in milliseconds. - * - * @return requestTimeoutInMs. + * Overrides the config default value + * @return the request timeout */ int getRequestTimeoutInMs(); @@ -216,8 +190,13 @@ public interface Request { */ String getBodyEncoding(); - boolean isUseRawUrl(); - ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy(); + + /** + * @return return true if request headers have been added, + * otherwise, returns false. + * + * @since 2.0 + */ + boolean hasHeaders(); } - diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilder.java b/api/src/main/java/org/asynchttpclient/RequestBuilder.java index 57f888ff95..52fef5a98a 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilder.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilder.java @@ -15,13 +15,15 @@ */ package org.asynchttpclient; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.multipart.Part; - import java.io.InputStream; import java.util.Collection; +import java.util.List; import java.util.Map; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.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, @@ -41,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 @@ -65,18 +75,28 @@ 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 addQueryParam(String name, String value) { + return super.addQueryParam(name, value); + } + + @Override + public RequestBuilder addQueryParams(List queryParams) { + return super.addQueryParams(queryParams); } @Override - public RequestBuilder addQueryParameter(String name, String value) { - return super.addQueryParameter(name, value); + public RequestBuilder setQueryParams(List params) { + return super.setQueryParams(params); } @Override - public RequestBuilder setQueryParameters(FluentStringsMap parameters) { - return super.setQueryParameters(parameters); + public RequestBuilder setQueryParams(Map> params) { + return super.setQueryParams(params); } @Override @@ -89,11 +109,6 @@ public RequestBuilder setBody(byte[] data) { return super.setBody(data); } - /** - * Set a Stream for chunking - * @param stream - An {@link InputStream} - * @return a {@link RequestBuilder} - */ @Override public RequestBuilder setBody(InputStream stream) { return super.setBody(stream); @@ -120,13 +135,13 @@ public RequestBuilder setHeaders(Map> headers) { } @Override - public RequestBuilder setParameters(Map> parameters) { - return super.setParameters(parameters); + public RequestBuilder setFormParams(List params) { + return super.setFormParams(params); } @Override - public RequestBuilder setParameters(FluentStringsMap parameters) { - return super.setParameters(parameters); + public RequestBuilder setFormParams(Map> params) { + return super.setFormParams(params); } @Override diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 4a881f0fa5..cd38530ac2 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -19,25 +19,20 @@ import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.StandardCharsets; -import org.asynchttpclient.util.UTF8UrlEncoder; +import org.asynchttpclient.util.QueryComputer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; 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; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; /** * Builder for {@link Request} @@ -47,26 +42,23 @@ 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 uri; private InetAddress address; private InetAddress localAddress; - private FluentCaseInsensitiveStringsMap headers; + private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); private ArrayList cookies; private byte[] byteData; private String stringData; private InputStream streamData; private BodyGenerator bodyGenerator; - private FluentStringsMap params; + private List formParams; private List parts; private String virtualHost; private long length = -1; - public FluentStringsMap queryParams; public ProxyServer proxyServer; private Realm realm; private File file; @@ -74,17 +66,16 @@ private static final class RequestImpl implements Request { private int requestTimeoutInMs; private long rangeOffset; public String charset; - private boolean useRawUrl; private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; + private List queryParams; - 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()); @@ -93,19 +84,17 @@ public RequestImpl(Request prototype) { this.stringData = prototype.getStringData(); this.streamData = prototype.getStreamData(); this.bodyGenerator = prototype.getBodyGenerator(); - this.params = (prototype.getParams() == null ? null : new FluentStringsMap(prototype.getParams())); - this.queryParams = (prototype.getQueryParams() == null ? null : new FluentStringsMap(prototype.getQueryParams())); - this.parts = (prototype.getParts() == null ? null : new ArrayList(prototype.getParts())); + this.formParams = prototype.getFormParams() == null ? null : new ArrayList(prototype.getFormParams()); + this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); this.virtualHost = prototype.getVirtualHost(); this.length = prototype.getContentLength(); 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(); - this.useRawUrl = prototype.isUseRawUrl(); this.connectionPoolKeyStrategy = prototype.getConnectionPoolKeyStrategy(); } } @@ -125,8 +114,8 @@ public InetAddress getLocalAddress() { return localAddress; } - private String removeTrailingSlash(URI uri) { - String uriString = uri.toString(); + private String removeTrailingSlash(UriComponents uri) { + String uriString = uri.toUrl(); if (uriString.endsWith("/")) { return uriString.substring(0, uriString.length() - 1); } else { @@ -140,91 +129,15 @@ public String getUrl() { } @Override - public String getRawUrl() { - return removeTrailingSlash(getRawURI()); - } - - public URI getOriginalURI() { - return originalUri; - } - - public URI getURI() { - if (uri == null) - uri = toURI(true); + public UriComponents getURI() { return uri; } - public URI getRawURI() { - if (rawUri == null) - rawUri = toURI(false); - return rawUri; - } - - private URI toURI(boolean encode) { - - if (originalUri == null) { - logger.debug("setUrl hasn't been invoked. Using http://localhost"); - originalUri = DEFAULT_REQUEST_URL; - } - - AsyncHttpProviderUtils.validateSupportedScheme(originalUri); - - StringBuilder builder = new StringBuilder(); - builder.append(originalUri.getScheme()).append("://").append(originalUri.getRawAuthority()); - if (isNonEmpty(originalUri.getRawPath())) { - builder.append(originalUri.getRawPath()); - } else { - builder.append("/"); - } - - if (isNonEmpty(queryParams)) { - - builder.append("?"); - - 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); - } else { - builder.append(name); - } - if (value != null) { - builder.append('='); - if (encode) { - UTF8UrlEncoder.appendEncoded(builder, value); - } else { - builder.append(value); - } - } - if (j.hasNext()) { - builder.append('&'); - } - } - if (i.hasNext()) { - builder.append('&'); - } - } - } - - return URI.create(builder.toString()); - } - @Override public FluentCaseInsensitiveStringsMap getHeaders() { - if (headers == null) { - headers = new FluentCaseInsensitiveStringsMap(); - } return headers; } - @Override - public boolean hasHeaders() { - return headers != null && !headers.isEmpty(); - } - @Override public Collection getCookies() { return cookies != null ? Collections.unmodifiableCollection(cookies) : Collections. emptyList(); @@ -256,13 +169,13 @@ public long getContentLength() { } @Override - public FluentStringsMap getParams() { - return params; + public List getFormParams() { + return formParams != null ? formParams : Collections. emptyList(); } @Override public List getParts() { - return parts; + return parts != null ? parts : Collections. emptyList(); } @Override @@ -270,11 +183,6 @@ public String getVirtualHost() { return virtualHost; } - @Override - public FluentStringsMap getQueryParams() { - return queryParams; - } - @Override public ProxyServer getProxyServer() { return proxyServer; @@ -291,13 +199,8 @@ public File getFile() { } @Override - public boolean isRedirectEnabled() { - return followRedirects != null && followRedirects; - } - - @Override - public boolean isRedirectOverrideSet() { - return followRedirects != null; + public Boolean getFollowRedirect() { + return followRedirects; } @Override @@ -305,95 +208,108 @@ public int getRequestTimeoutInMs() { return requestTimeoutInMs; } + @Override public long getRangeOffset() { return rangeOffset; } + @Override public String getBodyEncoding() { return charset; } + @Override public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { return connectionPoolKeyStrategy; } + @Override + public boolean hasHeaders() { + return headers != null && !headers.isEmpty(); + } + + @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()); + StringBuilder sb = new StringBuilder(getURI().toUrl()); sb.append("\t"); sb.append(method); sb.append("\theaders:"); - final FluentCaseInsensitiveStringsMap headersLocal = getHeaders(); - if (headersLocal != null) { - for (String name : headersLocal.keySet()) { + if (isNonEmpty(headers)) { + for (String name : headers.keySet()) { sb.append("\t"); sb.append(name); sb.append(":"); - sb.append(headersLocal.getJoinedValue(name, ", ")); + sb.append(headers.getJoinedValue(name, ", ")); } } - sb.append("\tparams:"); - if (params != null) { - for (String name : params.keySet()) { + if (isNonEmpty(formParams)) { + sb.append("\tformParams:"); + for (Param param : formParams) { sb.append("\t"); - sb.append(name); + sb.append(param.getName()); sb.append(":"); - sb.append(params.getJoinedValue(name, ", ")); + sb.append(param.getValue()); } } return sb.toString(); } - - public boolean isUseRawUrl() { - return useRawUrl; - } } private final Class derived; protected final RequestImpl request; - protected boolean useRawUrl = false; - /** - * Calculator used for calculating request signature for the request being - * built, if any. - */ + protected QueryComputer queryComputer; + protected List queryParams; protected SignatureCalculator signatureCalculator; - /** - * URL used as the base, not including possibly query parameters. Needed for - * signature calculation - */ - protected String baseURL; + protected RequestBuilderBase(Class derived, String method, boolean disableUrlEncoding) { + this(derived, method, QueryComputer.queryComputer(disableUrlEncoding)); + } - protected RequestBuilderBase(Class derived, String method, boolean rawUrls) { + protected RequestBuilderBase(Class derived, String method, QueryComputer queryComputer) { this.derived = derived; - request = new RequestImpl(rawUrls); + request = new RequestImpl(); request.method = method; - this.useRawUrl = rawUrls; + 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.useRawUrl = prototype.isUseRawUrl(); + this.queryComputer = queryComputer; } - + public T setUrl(String url) { - 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; - addQueryParameters(request.originalUri); - request.uri = null; - request.rawUri = null; + request.uri = uri; return derived.cast(this); } @@ -407,42 +323,13 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private void addQueryParameters(URI uri) { - if (isNonEmpty(uri.getRawQuery())) { - String[] queries = uri.getRawQuery().split("&"); - int pos; - for (String query : queries) { - pos = query.indexOf('='); - if (pos <= 0) { - addQueryParameter(query, null); - } else { - try { - if (useRawUrl) { - addQueryParameter(query.substring(0, pos), query.substring(pos + 1)); - } else { - addQueryParameter(URLDecoder.decode(query.substring(0, pos), StandardCharsets.UTF_8.name()), - URLDecoder.decode(query.substring(pos + 1), StandardCharsets.UTF_8.name())); - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - } - } - } - public T setVirtualHost(String virtualHost) { request.virtualHost = virtualHost; return derived.cast(this); } - public T setSignatureCalculator(SignatureCalculator signatureCalculator) { - this.signatureCalculator = signatureCalculator; - return derived.cast(this); - } - public T setHeader(String name, String value) { - request.getHeaders().replace(name, value); + request.headers.replace(name, value); return derived.cast(this); } @@ -452,19 +339,17 @@ public T addHeader(String name, String value) { value = ""; } - request.getHeaders().add(name, value); + request.headers.add(name, value); return derived.cast(this); } public T setHeaders(FluentCaseInsensitiveStringsMap headers) { - if (headers != null) - request.headers = new FluentCaseInsensitiveStringsMap(headers); + request.headers = (headers == null ? new FluentCaseInsensitiveStringsMap() : new FluentCaseInsensitiveStringsMap(headers)); return derived.cast(this); } public T setHeaders(Map> headers) { - if (headers != null) - request.headers = new FluentCaseInsensitiveStringsMap(headers); + request.headers = (headers == null ? new FluentCaseInsensitiveStringsMap() : new FluentCaseInsensitiveStringsMap(headers)); return derived.cast(this); } @@ -477,18 +362,18 @@ 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 resetCookies() { - if (request.cookies != null) - request.cookies.clear(); - } - public T addOrReplaceCookie(Cookie cookie) { String cookieKey = cookie.getName(); boolean replace = false; @@ -509,13 +394,18 @@ public T addOrReplaceCookie(Cookie cookie) { return derived.cast(this); } + public void resetCookies() { + if (request.cookies != null) + request.cookies.clear(); + } - public void resetQueryParameters() { - request.queryParams = null; + public void resetQuery() { + queryParams = null; + request.uri = request.uri.withNewQuery(null); } - - public void resetParameters() { - request.params = null; + + public void resetFormParams() { + request.formParams = null; } public void resetNonMultipartData() { @@ -535,7 +425,7 @@ public T setBody(File file) { } public T setBody(byte[] data) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.byteData = data; @@ -543,7 +433,7 @@ public T setBody(byte[] data) { } public T setBody(String data) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.stringData = data; @@ -551,7 +441,7 @@ public T setBody(String data) { } public T setBody(InputStream stream) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.streamData = stream; @@ -563,43 +453,63 @@ public T setBody(BodyGenerator bodyGenerator) { return derived.cast(this); } - public T addQueryParameter(String name, String value) { - if (request.queryParams == null) - request.queryParams = new FluentStringsMap(); - request.queryParams.add(name, value); + public T addQueryParam(String name, String value) { + if (queryParams == null) { + queryParams = new ArrayList(1); + } + queryParams.add(new Param(name, value)); return derived.cast(this); } - public T setQueryParameters(FluentStringsMap parameters) { - request.queryParams = parameters != null? new FluentStringsMap(parameters) : null; + public T addQueryParams(List queryParams) { + for (Param queryParam: queryParams) + addQueryParam(queryParam.getName(), queryParam.getValue()); return derived.cast(this); } - public T addParameter(String key, String value) { - resetNonMultipartData(); - resetMultipartData(); - if (request.params == null) - request.params = new FluentStringsMap(); - request.params.add(key, value); - return derived.cast(this); + 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 params; + } + + public T setQueryParams(Map> map) { + return setQueryParams(map2ParamList(map)); } - public T setParameters(FluentStringsMap parameters) { + public T setQueryParams(List params) { + queryParams = params; + return derived.cast(this); + } + + public T addFormParam(String name, String value) { resetNonMultipartData(); resetMultipartData(); - request.params = 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 setParameters(Map> parameters) { + public T setFormParams(Map> map) { + return setFormParams(map2ParamList(map)); + } + public T setFormParams(List params) { resetNonMultipartData(); resetMultipartData(); - request.params = new FluentStringsMap(parameters); + request.formParams = params; return derived.cast(this); } public T addBodyPart(Part part) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); if (request.parts == null) request.parts = new ArrayList(); @@ -647,21 +557,20 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe return derived.cast(this); } + public T setSignatureCalculator(SignatureCalculator signatureCalculator) { + this.signatureCalculator = signatureCalculator; + return derived.cast(this); + } + 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) */ if (signatureCalculator != null) { - String url = baseURL != null? baseURL : request.originalUri.toString(); - // Should not include query parameters, ensure: - int i = url.indexOf('?'); - if (i >= 0) { - url = url.substring(0, i); - } - signatureCalculator.calculateAndAddSignature(url, request, this); - } + signatureCalculator.calculateAndAddSignature(request, this); + } } - + private void computeRequestCharset() { if (request.charset == null) { try { @@ -679,29 +588,50 @@ private void computeRequestCharset() { } } } - - private void computeRequestContentLength() { + + private void computeRequestLength() { if (request.length < 0 && request.streamData == null) { // can't concatenate content-length - String contentLength = null; - if (request.headers != null && request.headers.isEmpty()) { - contentLength = request.headers.getFirstValue("Content-Length"); - } + final String contentLength = request.headers.getFirstValue("Content-Length"); if (contentLength != null) { try { request.length = Long.parseLong(contentLength); } catch (NumberFormatException e) { - // NoOp -- we won't specify length so it will be chunked? + // NoOp -- we wdn't specify length so it will be chunked? } } } } + 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 = queryComputer.computeFullQueryString(request.uri.getQuery(), queryParams); + + request.uri = new UriComponents(// + request.uri.getScheme(),// + request.uri.getUserInfo(),// + request.uri.getHost(),// + request.uri.getPort(),// + newPath,// + newQuery); + } + public Request build() { + computeFinalUri(); executeSignatureCalculator(); computeRequestCharset(); - computeRequestContentLength(); + computeRequestLength(); return request; } } + diff --git a/api/src/main/java/org/asynchttpclient/Response.java b/api/src/main/java/org/asynchttpclient/Response.java index 998e883501..9c58ae1f49 100644 --- a/api/src/main/java/org/asynchttpclient/Response.java +++ b/api/src/main/java/org/asynchttpclient/Response.java @@ -17,11 +17,10 @@ package org.asynchttpclient; import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.uri.UriComponents; 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.List; @@ -111,12 +110,11 @@ 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 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 URI}. - * @throws MalformedURLException + * @return the request {@link UriComponents}. */ - URI getUri() throws MalformedURLException; + UriComponents getUri(); /** * Return the content-type header value. diff --git a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java index 2f907b9390..90339d8c59 100644 --- a/api/src/main/java/org/asynchttpclient/SignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/SignatureCalculator.java @@ -35,7 +35,6 @@ public interface SignatureCalculator { * @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/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index b96d69a91f..3ea5d1e72c 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -26,6 +26,7 @@ import java.io.Closeable; 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; @@ -360,6 +361,11 @@ public enum ErrorDocumentBehaviour { OMIT; } + /** + * This interface contains possible configuration changes for a derived SimpleAsyncHttpClient. + * + * @see SimpleAsyncHttpClient#derive() + */ /** * This interface contains possible configuration changes for a derived SimpleAsyncHttpClient. * @@ -373,9 +379,9 @@ public interface DerivedBuilder { DerivedBuilder setUrl(String url); - DerivedBuilder setParameters(FluentStringsMap parameters); + DerivedBuilder setFormParams(List params); - DerivedBuilder setParameters(Map> parameters); + DerivedBuilder setFormParams(Map> params); DerivedBuilder setHeaders(Map> headers); @@ -383,9 +389,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); @@ -443,13 +449,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; } @@ -468,13 +474,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(List params) { + requestBuilder.setFormParams(params); return this; } diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java index b5d75a4faa..5103a8be5b 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java @@ -16,10 +16,13 @@ */ package org.asynchttpclient.oauth; -import org.asynchttpclient.FluentStringsMap; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + +import org.asynchttpclient.Param; import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilderBase; import org.asynchttpclient.SignatureCalculator; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.Base64; import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.util.UTF8UrlEncoder; @@ -27,7 +30,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Random; /** @@ -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.getParams(), 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,8 +94,8 @@ 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) { + 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) signedText.append('&'); @@ -102,18 +103,23 @@ 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); - } - } - signedText.append(UTF8UrlEncoder.encode(baseURL)); + String scheme = uri.getScheme(); + int port = uri.getPort(); + 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) + sb.append(':').append(port); + if (isNonEmpty(uri.getPath())) + sb.append(uri.getPath()); + + String baseURL = sb.toString(); + UTF8UrlEncoder.appendEncoded(signedText, baseURL); /** * List of all query and form parameters added to this request; needed @@ -132,19 +138,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(); @@ -189,7 +189,7 @@ private synchronized String generateNonce() { random.nextBytes(nonceBuffer); // let's use base64 encoding over hex, slightly more compact than hex or decimals return Base64.encode(nonceBuffer); - // return String.valueOf(Math.abs(random.nextLong())); +// return String.valueOf(Math.abs(random.nextLong())); } /** @@ -265,17 +265,13 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; Parameter parameter = (Parameter) o; - if (!key.equals(parameter.key)) - return false; - if (!value.equals(parameter.value)) - return false; + if (!key.equals(parameter.key)) return false; + if (!value.equals(parameter.value)) return false; return true; } diff --git a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java index d2b4fc225f..66b39a2d4b 100644 --- a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java +++ b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java @@ -8,9 +8,9 @@ import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Response; import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; -import java.net.URI; import java.util.Collections; import java.util.List; @@ -51,7 +51,7 @@ public final String getStatusText() { } @Override - public final URI getUri() { + public final UriComponents getUri() { return status.getUri(); } diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index 53101d590a..c7fd13d75a 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -103,7 +103,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().toURL().toString(); + url = status.getUri().toUrl(); } else { return AsyncHandler.STATE.ABORT; } diff --git a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java new file mode 100644 index 0000000000..898557d6a5 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.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(toUrl()); + } + + 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(); + } + + @Override + public String toString() { + // for now, but might change + return toUrl(); + } + + 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/api/src/main/java/org/asynchttpclient/uri/UriComponentsParser.java b/api/src/main/java/org/asynchttpclient/uri/UriComponentsParser.java new file mode 100644 index 0000000000..b6ee9c9f1f --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/uri/UriComponentsParser.java @@ -0,0 +1,340 @@ +/* + * 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 org.asynchttpclient.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/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 1f614a507d..3e95e67ea6 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -12,15 +12,16 @@ */ package org.asynchttpclient.util; +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.Request; +import org.asynchttpclient.uri.UriComponents; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; import java.nio.charset.Charset; import java.util.List; @@ -39,7 +40,7 @@ public class AsyncHttpProviderUtils { public final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; - 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")) { @@ -48,36 +49,22 @@ 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(); 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) != '/') { - throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); - } else if (path.length() == 0) { - return URI.create(u + "/"); + 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(URI 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; - } - /** * @param bodyParts NON EMPTY body part * @param maxLen @@ -117,60 +104,16 @@ public final static byte[] contentToBytes(List bodyParts, return result; } - public final static String getHost(URI uri) { - String host = uri.getHost(); - if (host == null) { - host = uri.getAuthority(); - } - return host; + public final static String getBaseUrl(UriComponents uri) { + return uri.getScheme() + "://" + getAuthority(uri); } - 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 String getAuthority(UriComponents uri) { + int port = uri.getPort() != -1? uri.getPort() : getDefaultPort(uri); + return uri.getHost() + ":" + port; } - 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; @@ -208,4 +151,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 followRedirect(AsyncHttpClientConfig config, Request request) { + return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isFollowRedirect(); + } } diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index 1b183dd3e8..16fd18207f 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -19,6 +19,7 @@ import org.asynchttpclient.ProxyServer.Protocol; import org.asynchttpclient.ProxyServerSelector; import org.asynchttpclient.Request; +import org.asynchttpclient.uri.UriComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,8 +27,8 @@ import java.net.Proxy; import java.net.ProxySelector; import java.net.URI; +import java.net.URISyntaxException; import java.util.List; -import java.util.Locale; import java.util.Properties; /** @@ -84,17 +85,17 @@ 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; } - + /** * @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.getURI().getHost()); } private static boolean matchNonProxyHost(String targetHost, String nonProxyHost) { @@ -199,30 +200,36 @@ public static ProxyServerSelector getJdkDefaultProxyServerSelector() { */ public static ProxyServerSelector createProxyServerSelector(final ProxySelector proxySelector) { return new ProxyServerSelector() { - @Override - 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()); + 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()); + return null; + } else { + InetSocketAddress address = (InetSocketAddress) proxy.address(); + return new ProxyServer(Protocol.HTTP, address.getHostName(), address.getPort()); + } + case DIRECT: return null; - } else { - InetSocketAddress address = (InetSocketAddress) proxy.address(); - return new ProxyServer(Protocol.HTTP, address.getHostName(), address.getPort()); + default: + log.warn("ProxySelector returned proxy type that we don't know how to use: " + proxy.type()); + break; } - case DIRECT: - return null; - 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; } }; } @@ -235,8 +242,7 @@ public ProxyServer select(URI uri) { */ public static ProxyServerSelector createProxyServerSelector(final ProxyServer proxyServer) { return new ProxyServerSelector() { - @Override - public ProxyServer select(URI uri) { + public ProxyServer select(UriComponents uri) { return proxyServer; } }; diff --git a/api/src/main/java/org/asynchttpclient/util/QueryComputer.java b/api/src/main/java/org/asynchttpclient/util/QueryComputer.java new file mode 100644 index 0000000000..058c070c0e --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/util/QueryComputer.java @@ -0,0 +1,140 @@ +/* + * 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 org.asynchttpclient.util; + +import java.util.List; + +import static org.asynchttpclient.util.MiscUtil.isNonEmpty; + +import org.asynchttpclient.Param; + +public enum QueryComputer { + + URL_ENCODING_ENABLED_QUERY_COMPUTER { + + private final void encodeAndAppendQueryParam(final StringBuilder sb, final CharSequence name, final CharSequence 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()); + } + + // FIXME this could be improved: remove split + private final void encodeAndAppendQuery(final StringBuilder sb, final String query) { + int pos; + for (String queryParamString : query.split("&")) { + pos = queryParamString.indexOf('='); + if (pos <= 0) { + CharSequence decodedName = UTF8UrlDecoder.decode(queryParamString); + encodeAndAppendQueryParam(sb, decodedName, null); + } else { + CharSequence decodedName = UTF8UrlDecoder.decode(queryParamString, 0, pos); + int valueStart = pos + 1; + CharSequence decodedValue = UTF8UrlDecoder.decode(queryParamString, valueStart, queryParamString.length() - 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() + queryParams.size() * 16); + encodeAndAppendQuery(sb, query); + encodeAndAppendQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected final String withQueryWithoutParams(final String query) { + // encode query + StringBuilder sb = new StringBuilder(query.length() + 6); + encodeAndAppendQuery(sb, query); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected final 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 { + + 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.length() + queryParams.size() * 16); + sb.append(query); + appendRawQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected final String withQueryWithoutParams(final String query) { + // return raw query as is + return query; + } + + protected final 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 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); + } +} diff --git a/api/src/main/java/org/asynchttpclient/util/StringCharSequence.java b/api/src/main/java/org/asynchttpclient/util/StringCharSequence.java new file mode 100644 index 0000000000..a1cf2192f2 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.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/api/src/main/java/org/asynchttpclient/util/UTF8UrlDecoder.java b/api/src/main/java/org/asynchttpclient/util/UTF8UrlDecoder.java new file mode 100644 index 0000000000..7184aea114 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/util/UTF8UrlDecoder.java @@ -0,0 +1,70 @@ +/* + * 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 org.asynchttpclient.util; + +public final class UTF8UrlDecoder { + + private UTF8UrlDecoder() { + } + + 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, offset, i); + } + } + + private static int hexaDigit(char c) { + return Character.digit(c, 16); + } + + public static CharSequence decode(String s) { + return decode(s, 0, s.length()); + } + + public static CharSequence decode(final String s, final int offset, final int length) { + + StringBuilder sb = null; + int i = offset; + int end = length + offset; + + while (i < end) { + char c = s.charAt(i); + if (c == '+') { + sb = initSb(sb, s, i, offset, length); + sb.append(' '); + i++; + + } else if (c == '%') { + 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; + 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, offset, length); + sb.append((char) (x * 16 + y)); + i += 3; + } else { + if (sb != null) + sb.append(c); + i++; + } + } + + return sb != null ? sb.toString() : new StringCharSequence(s, offset, length); + } +} diff --git a/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java b/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java index 765a67f368..78cb74d9e0 100644 --- a/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java +++ b/api/src/main/java/org/asynchttpclient/util/UTF8UrlEncoder.java @@ -26,25 +26,25 @@ public class UTF8UrlEncoder { * 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(); + private static final char[] HEX = "0123456789ABCDEF".toCharArray(); private UTF8UrlEncoder() { } @@ -55,25 +55,22 @@ public static String encode(String input) { return sb.toString(); } - 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) { + 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; } - private static void appendSingleByteEncoded(StringBuilder sb, int value) { + private final static void appendSingleByteEncoded(StringBuilder sb, int value) { if (encodeSpaceUsingPlus && value == 32) { sb.append('+'); @@ -85,7 +82,7 @@ private static void appendSingleByteEncoded(StringBuilder sb, int value) { sb.append(HEX[value & 0xF]); } - private static void appendMultiByteEncoded(StringBuilder sb, int value) { + private final static void appendMultiByteEncoded(StringBuilder sb, int value) { if (value < 0x800) { appendSingleByteEncoded(sb, (0xc0 | (value >> 6))); appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); @@ -100,5 +97,4 @@ private static void appendMultiByteEncoded(StringBuilder sb, int value) { appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); } } - } diff --git a/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java b/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java index 347d5127ef..6d3b0e0a60 100644 --- a/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java +++ b/api/src/main/java/org/asynchttpclient/webdav/WebDavCompletionHandlerBase.java @@ -13,6 +13,16 @@ package org.asynchttpclient.webdav; +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 javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; @@ -21,6 +31,7 @@ import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Response; import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.uri.UriComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -29,18 +40,6 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -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; - /** * Simple {@link AsyncHandler} that add support for WebDav's response manipulation. * @@ -180,7 +179,7 @@ public String getResponseBody() throws IOException { } @Override - public URI getUri() throws MalformedURLException { + public UriComponents getUri() { return wrappedResponse.getUri(); } diff --git a/api/src/main/java/org/asynchttpclient/webdav/WebDavResponse.java b/api/src/main/java/org/asynchttpclient/webdav/WebDavResponse.java index 69de7e2da8..cbeb2ad0b1 100644 --- a/api/src/main/java/org/asynchttpclient/webdav/WebDavResponse.java +++ b/api/src/main/java/org/asynchttpclient/webdav/WebDavResponse.java @@ -12,18 +12,17 @@ */ package org.asynchttpclient.webdav; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.Response; -import org.asynchttpclient.cookie.Cookie; -import org.w3c.dom.Document; - import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; import java.nio.ByteBuffer; import java.util.List; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.Response; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.uri.UriComponents; +import org.w3c.dom.Document; + /** * Customized {@link Response} which add support for getting the response's body as an XML document (@link WebDavResponse#getBodyAsXML} */ @@ -74,7 +73,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/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index accbe651a7..2a17d861d5 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -49,7 +49,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; @@ -95,7 +94,7 @@ public void onThrowable(Throwable t) { public void asyncProviderEncodingTest2() throws Exception { 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(); String url = client.executeRequest(request, new AsyncCompletionHandler() { @Override @@ -288,11 +287,11 @@ public void asyncParamPOSTTest() throws Exception { 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)); } - 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 @@ -501,7 +500,7 @@ public void asyncDoPostDefaultContentType() throws Exception { 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 { @@ -756,11 +755,11 @@ public void asyncRequestVirtualServerPOSTTest() throws Exception { 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)); } - 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/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 80838a4f7e..985b077695 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -97,7 +97,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(); @@ -142,7 +142,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 @@ -182,7 +182,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 @@ -262,7 +262,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/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java b/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java index e7bd9dd9fa..f423831b01 100644 --- a/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java +++ b/api/src/test/java/org/asynchttpclient/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/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java index 746e2390bd..90e99a4567 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java @@ -22,25 +22,25 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.io.IOException; +import java.net.ConnectException; +import java.util.Enumeration; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; +import org.asynchttpclient.uri.UriComponents; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.IOException; -import java.net.ConnectException; -import java.net.URI; -import java.util.Enumeration; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; - public abstract class PerRequestRelative302Test extends AbstractBasicTest { private final AtomicBoolean isSet = new AtomicBoolean(false); @@ -123,7 +123,7 @@ public void notRedirected302Test() throws Exception { } } - private String getBaseUrl(URI uri) { + private String getBaseUrl(UriComponents uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -133,7 +133,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/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java index 3907683f9d..80865b5e6b 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java @@ -87,7 +87,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 @@ -122,7 +122,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/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java b/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java index d2356e782c..fe8909583a 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java +++ b/api/src/test/java/org/asynchttpclient/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.getUri().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=")) { - throw new IOException(status.getUri().toURL().toString()); + if (!status.getUri().toUrl().equals("http://127.0.0.1/" + port1 + "/?a=")) { + throw new IOException(status.getUri().toUrl()); } 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.getUri().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c&d=e")) { + if (!status.getUri().toUrl().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.getUri().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e")) { + if (!status.getUri().toUrl().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/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java index 7d267111ca..cfd3b37db4 100644 --- a/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java +++ b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java @@ -74,7 +74,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); @@ -103,20 +103,7 @@ public void testUrlRequestParametersEncoding() throws IOException, ExecutionExce } @Test(groups = { "standalone", "default_provider" }) - public void urlWithColonTest_Netty() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); - try { - String query = "test:colon:"; - Response response = c.prepareGet(String.format("http://127.0.0.1:%d/foo/test/colon?q=%s", port1, query)).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - - assertEquals(response.getHeader("q"), URLEncoder.encode(query, StandardCharsets.UTF_8.name())); - } finally { - c.close(); - } - } - - @Test(groups = { "standalone", "default_provider" }) - public void urlWithColonTest_JDK() throws Exception { + public void urlWithColonTest() throws Exception { AsyncHttpClient c = getAsyncHttpClient(null); try { String query = "test:colon:"; diff --git a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java index 9eb0cadef0..56fac7b88b 100644 --- a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java @@ -22,25 +22,26 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +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; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; +import org.asynchttpclient.uri.UriComponents; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.IOException; -import java.net.ConnectException; -import java.net.URI; -import java.util.Enumeration; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; - public abstract class Relative302Test extends AbstractBasicTest { private final AtomicBoolean isSet = new AtomicBoolean(false); @@ -167,7 +168,7 @@ public void relativePathRedirectTest() throws Exception { } } - private String getBaseUrl(URI uri) { + private String getBaseUrl(UriComponents uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -177,7 +178,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/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java index a6e9214ab4..fe560de3ac 100644 --- a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java @@ -17,15 +17,16 @@ import static org.testng.Assert.assertEquals; -import org.asynchttpclient.FluentStringsMap; -import org.asynchttpclient.Request; -import org.asynchttpclient.RequestBuilder; -import org.testng.annotations.Test; - import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.List; import java.util.concurrent.ExecutionException; +import org.asynchttpclient.Param; +import org.asynchttpclient.Request; +import org.asynchttpclient.RequestBuilder; +import org.testng.annotations.Test; + public class RequestBuilderTest { private final static String SAFE_CHARS = @@ -54,7 +55,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 +78,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,14 +90,14 @@ 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"); - 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/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java b/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java index 69b36f1e1d..268cd58e98 100644 --- a/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java +++ b/api/src/test/java/org/asynchttpclient/oauth/TestSignatureCalculator.java @@ -17,7 +17,11 @@ import static org.testng.Assert.assertEquals; -import org.asynchttpclient.FluentStringsMap; +import java.util.ArrayList; +import java.util.List; + +import org.asynchttpclient.Param; +import org.asynchttpclient.uri.UriComponents; import org.testng.annotations.Test; public class TestSignatureCalculator { @@ -40,11 +44,11 @@ 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); + String sig = calc.calculateSignature("GET", UriComponents.create(url), TIMESTAMP, NONCE, null, queryParams); assertEquals(sig, "tR3+Ty81lMeYAr/Fid0kMTYa/WM="); } diff --git a/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java b/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java deleted file mode 100644 index 06ab8fbc12..0000000000 --- a/api/src/test/java/org/asynchttpclient/util/AsyncHttpProviderUtilsTest.java +++ /dev/null @@ -1,47 +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 org.asynchttpclient.util; - -import static org.testng.Assert.assertEquals; - -import org.testng.annotations.Test; - -import java.net.URI; - -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); - assertEquals( uri.toString(), "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"); - } - - @Test(groups = "fast") - public void getRedirectUriShouldHandleRawQueryParamsLocation() { - - String url = "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"; - URI uri = AsyncHttpProviderUtils.getRedirectUri(URI.create("http://www.ebay.de/"), url); - assertEquals(uri.toString(), "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"); - } - - @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); - assertEquals(uri.toString(), "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"); - } -} diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index e90f418664..3130f83f51 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -20,6 +20,7 @@ import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.Base64; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; @@ -45,7 +46,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.net.URI; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -134,7 +134,7 @@ public void doTrackedConnection(final Request request,// } public Connection obtainConnection(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, - InterruptedException, TimeoutException { + InterruptedException, TimeoutException, IOException { final Connection c = obtainConnection0(request, requestFuture); markConnectionAsDoNotCache(c); @@ -146,7 +146,7 @@ public Connection obtainConnection(final Request request, final GrizzlyResponseF static CompletionHandler wrapHandler(final Request request, final HostnameVerifier verifier, final CompletionHandler delegate, final SSLFilter sslFilter) { - final URI uri = request.getURI(); + final UriComponents uri = request.getURI(); if (Utils.isSecure(uri) && verifier != null) { SSLBaseFilter.HandshakeListener handshakeListener = new SSLBaseFilter.HandshakeListener() { @Override @@ -190,7 +190,7 @@ private HostnameVerifier getVerifier() { return provider.getClientConfig().getHostnameVerifier(); } - private EndpointKey getEndPointKey(final Request request, final ProxyServer proxyServer) { + private EndpointKey getEndPointKey(final Request request, final ProxyServer proxyServer) throws IOException { final String stringKey = getPoolKey(request, proxyServer); EndpointKey key = endpointKeyMap.get(stringKey); if (key == null) { @@ -203,6 +203,7 @@ private EndpointKey getEndPointKey(final Request request, final P if (localAddress != null) { localSocketAddress = new InetSocketAddress(localAddress.getHostName(), 0); } + ProxyAwareConnectorHandler handler = ProxyAwareConnectorHandler.builder(provider.clientTransport) .nonSecureFilterChainTemplate(nonSecureBuilder).secureFilterChainTemplate(secureBuilder) .asyncHttpClientConfig(provider.getClientConfig()).uri(request.getURI()).proxyServer(proxyServer).build(); @@ -216,13 +217,13 @@ private EndpointKey getEndPointKey(final Request request, final P } private SocketAddress getRemoteAddress(final Request request, final ProxyServer proxyServer) { - final URI requestUri = request.getURI(); + final UriComponents requestUri = request.getURI(); final String host = ((proxyServer != null) ? proxyServer.getHost() : requestUri.getHost()); final int port = ((proxyServer != null) ? proxyServer.getPort() : requestUri.getPort()); return new InetSocketAddress(host, getPort(request.getURI(), port)); } - private static int getPort(final URI uri, final int p) { + private static int getPort(final UriComponents uri, final int p) { int port = p; if (port == -1) { final String protocol = uri.getScheme().toLowerCase(Locale.ENGLISH); @@ -238,7 +239,7 @@ private static int getPort(final URI uri, final int p) { } private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, - InterruptedException, TimeoutException { + InterruptedException, TimeoutException, IOException { final int cTimeout = provider.getClientConfig().getConnectionTimeoutInMs(); final FutureImpl future = Futures.createSafeFuture(); @@ -246,6 +247,7 @@ private Connection obtainConnection0(final Request request, final GrizzlyRespons createConnectionCompletionHandler(request, requestFuture, null)); final ProxyServer proxyServer = requestFuture.getProxyServer(); final SocketAddress address = getRemoteAddress(request, proxyServer); + ProxyAwareConnectorHandler handler = ProxyAwareConnectorHandler.builder(provider.clientTransport) .nonSecureFilterChainTemplate(nonSecureBuilder)// .secureFilterChainTemplate(secureBuilder)// diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 934bc52bc4..dd8d457fd6 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -34,6 +34,7 @@ import org.asynchttpclient.providers.grizzly.statushandler.RedirectHandler; import org.asynchttpclient.providers.grizzly.statushandler.StatusHandler; import org.asynchttpclient.providers.grizzly.websocket.GrizzlyWebSocketAdapter; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.filterchain.FilterChainContext; @@ -49,7 +50,6 @@ import org.glassfish.grizzly.websockets.SimpleWebSocket; import org.glassfish.grizzly.websockets.WebSocketHolder; -import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -367,14 +367,7 @@ private static GrizzlyWebSocketAdapter createWebSocketAdapter(final HttpTxContex } private static boolean isRedirectAllowed(final HttpTxContext ctx) { - boolean allowed = ctx.getRequest().isRedirectEnabled(); - if (ctx.getRequest().isRedirectOverrideSet()) { - return allowed; - } - if (!allowed) { - allowed = ctx.isRedirectsAllowed(); - } - return allowed; + return ctx.getRequest().getFollowRedirect() != null? ctx.getRequest().getFollowRedirect().booleanValue() : ctx.isRedirectsAllowed(); } @SuppressWarnings("rawtypes") @@ -413,7 +406,7 @@ public static boolean isRedirect(final int status) { // ----------------------------------------------------- Private Methods - public static Request newRequest(final URI uri, final HttpResponsePacket response, final HttpTxContext ctx, boolean asGet) { + public static Request newRequest(final UriComponents uri, final HttpResponsePacket response, final HttpTxContext ctx, boolean asGet) { final RequestBuilder builder = new RequestBuilder(ctx.getRequest()); if (asGet) { @@ -421,9 +414,9 @@ public static Request newRequest(final URI uri, final HttpResponsePacket respons } builder.setUrl(uri.toString()); - if (ctx.getProvider().getClientConfig().isRemoveQueryParamOnRedirect()) { - builder.setQueryParameters(null); - } + if (!ctx.getProvider().getClientConfig().isRemoveQueryParamOnRedirect()) + builder.addQueryParams(ctx.getRequest().getQueryParams()); + if (response.getHeader(Header.Cookie) != null) { for (String cookieStr : response.getHeaders().values(Header.Cookie)) { Cookie c = CookieDecoder.decode(cookieStr); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java index 8aa2e02cb4..328a75735e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponseStatus.java @@ -18,9 +18,9 @@ import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Response; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.http.HttpResponsePacket; -import java.net.URI; import java.util.List; /** @@ -42,7 +42,7 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { // ------------------------------------------------------------ Constructors - public GrizzlyResponseStatus(final HttpResponsePacket response, final URI uri, AsyncHttpClientConfig config) { + public GrizzlyResponseStatus(final HttpResponsePacket response, final UriComponents uri, AsyncHttpClientConfig config) { super(uri, config); statusCode = response.getStatus(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index a12fc65748..308558b228 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java @@ -95,7 +95,7 @@ private HttpTxContext(final GrizzlyAsyncHttpProvider provider, final GrizzlyResp this.future = future; this.request = request; this.handler = handler; - redirectsAllowed = this.provider.getClientConfig().isRedirectEnabled(); + redirectsAllowed = this.provider.getClientConfig().isFollowRedirect(); maxRedirectCount = this.provider.getClientConfig().getMaxRedirects(); this.requestUrl = request.getUrl(); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java index c0e1b1fc4c..adff9edb41 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ProxyAwareConnectorHandler.java @@ -17,6 +17,7 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.providers.grizzly.filters.ProxyFilter; import org.asynchttpclient.providers.grizzly.filters.TunnelFilter; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.Processor; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; @@ -24,14 +25,12 @@ import org.glassfish.grizzly.nio.transport.TCPNIOConnectorHandler; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; -import java.net.URI; - final class ProxyAwareConnectorHandler extends TCPNIOConnectorHandler { private FilterChainBuilder nonSecureTemplate; private FilterChainBuilder secureTemplate; private AsyncHttpClientConfig clientConfig; - private URI uri; + private UriComponents uri; private ProxyServer proxyServer; // ------------------------------------------------------------ Constructors @@ -113,7 +112,7 @@ public Builder asyncHttpClientConfig(final AsyncHttpClientConfig clientConfig) { return this; } - public Builder uri(final URI uri) { + public Builder uri(final UriComponents uri) { connectorHandler.uri = uri; return this; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java index 340b70527f..4a4a434cca 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java @@ -13,12 +13,12 @@ package org.asynchttpclient.providers.grizzly; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.attributes.AttributeStorage; -import java.net.URI; import java.util.concurrent.atomic.AtomicInteger; public final class Utils { @@ -36,7 +36,7 @@ private Utils() { // ---------------------------------------------------------- Public Methods - public static boolean isSecure(final URI uri) { + public static boolean isSecure(final UriComponents uri) { final String scheme = uri.getScheme(); return ("https".equals(scheme) || "wss".equals(scheme)); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java index 69c4a63236..afe14577ce 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java @@ -15,7 +15,7 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import org.asynchttpclient.FluentStringsMap; +import org.asynchttpclient.Param; import org.asynchttpclient.Request; import org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider; import org.glassfish.grizzly.Buffer; @@ -29,7 +29,6 @@ import java.io.IOException; import java.net.URLEncoder; import java.util.List; -import java.util.Map; public final class ParamsBodyHandler extends BodyHandler { @@ -42,7 +41,7 @@ public ParamsBodyHandler(GrizzlyAsyncHttpProvider grizzlyAsyncHttpProvider) { // -------------------------------------------- Methods from BodyHandler public boolean handlesBodyType(final Request request) { - final FluentStringsMap params = request.getParams(); + final List params = request.getFormParams(); return isNonEmpty(params); } @@ -57,24 +56,16 @@ public boolean doHandle(final FilterChainContext ctx, final Request request, fin if (charset == null) { charset = Charsets.ASCII_CHARSET.name(); } - final FluentStringsMap params = request.getParams(); + final List 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 (int i = 0, len = values.size(); i < len; i++) { - final String value = values.get(i); - if (sb.length() > 0) { - sb.append('&'); - } - sb.append(URLEncoder.encode(name, charset)).append('=').append(URLEncoder.encode(value, charset)); - } - } + if (sb == null) { + sb = new StringBuilder(128); + } + for (Param param : params) { + sb.append(URLEncoder.encode(param.getName(), charset)).append('=').append(URLEncoder.encode(param.getValue(), charset)); + sb.append('&'); } + sb.setLength(sb.length() - 1); } if (sb != null) { final byte[] data = sb.toString().getBytes(charset); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 90e57d95d1..80db9da2a9 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -20,12 +20,10 @@ import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; - import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.FluentStringsMap; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; import org.asynchttpclient.Request; @@ -45,7 +43,7 @@ import org.asynchttpclient.providers.grizzly.filters.events.ContinueEvent; import org.asynchttpclient.providers.grizzly.filters.events.SSLSwitchingEvent; import org.asynchttpclient.providers.grizzly.filters.events.TunnelRequestEvent; -import org.asynchttpclient.util.StandardCharsets; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; @@ -74,10 +72,8 @@ import org.slf4j.Logger; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLEncoder; import java.util.Collection; import java.util.List; import java.util.Map; @@ -158,7 +154,7 @@ public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEve ctx.suspend(); TunnelRequestEvent tunnelRequestEvent = (TunnelRequestEvent) event; final ProxyServer proxyServer = tunnelRequestEvent.getProxyServer(); - final URI requestUri = tunnelRequestEvent.getUri(); + final UriComponents requestUri = tunnelRequestEvent.getUri(); RequestBuilder builder = new RequestBuilder(); builder.setMethod(Method.CONNECT.getMethodString()); @@ -211,7 +207,7 @@ private boolean sendAsGrizzlyRequest( } final Request request = httpTxContext.getRequest(); - final URI uri = request.isUseRawUrl() ? request.getRawURI() : request.getURI(); + final UriComponents uri = request.getURI(); boolean secure = Utils.isSecure(uri); // If the request is secure, check to see if an error occurred during @@ -419,7 +415,7 @@ private static FilterChainContext obtainProtocolChainContext(final FilterChainCo return newFilterChainContext; } - private static void addHostHeader(final Request request, final URI uri, final HttpRequestPacket requestPacket) { + private static void addHostHeader(final Request request, final UriComponents uri, final HttpRequestPacket requestPacket) { String host = request.getVirtualHost(); if (host != null) { requestPacket.addHeader(Header.Host, host); @@ -542,31 +538,9 @@ private static void convertCookies(final Collection cookies, final org.g private static 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, StandardCharsets.UTF_8.name())).append('=') - .append(URLEncoder.encode(values.get(i), StandardCharsets.UTF_8.name())).append('&'); - } else { - sb.append(URLEncoder.encode(name, StandardCharsets.UTF_8.name())).append('&'); - } - } - } catch (UnsupportedEncodingException ignored) { - } - } - } - sb.setLength(sb.length() - 1); - String queryString = sb.toString(); - - requestPacket.setQueryString(queryString); + String query = request.getURI().getQuery(); + if (isNonEmpty(query)) { + requestPacket.setQueryString(query); } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java index 081fd60314..ed9723fa96 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java @@ -13,18 +13,18 @@ package org.asynchttpclient.providers.grizzly.filters; +import java.io.IOException; + import org.asynchttpclient.ProxyServer; import org.asynchttpclient.providers.grizzly.Utils; import org.asynchttpclient.providers.grizzly.filters.events.TunnelRequestEvent; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.IOEvent; import org.glassfish.grizzly.filterchain.BaseFilter; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.filterchain.FilterChainEvent; import org.glassfish.grizzly.filterchain.NextAction; -import java.io.IOException; -import java.net.URI; - /** * This Filter is responsible for HTTP CONNECT * tunnelling when a connection should be secure and required to @@ -36,11 +36,11 @@ public final class TunnelFilter extends BaseFilter { private final ProxyServer proxyServer; - private final URI uri; + private final UriComponents uri; // ------------------------------------------------------------ Constructors - public TunnelFilter(final ProxyServer proxyServer, final URI uri) { + public TunnelFilter(final ProxyServer proxyServer, final UriComponents uri) { this.proxyServer = proxyServer; this.uri = uri; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java index 41f49894c4..0e403dd014 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/events/TunnelRequestEvent.java @@ -13,11 +13,10 @@ package org.asynchttpclient.providers.grizzly.filters.events; import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.filterchain.FilterChainEvent; -import java.net.URI; - /** * {@link FilterChainEvent} to initiate CONNECT tunnelling with a proxy server. * @@ -28,11 +27,11 @@ public final class TunnelRequestEvent implements FilterChainEvent { private final FilterChainContext suspendedContext; private final ProxyServer proxyServer; - private final URI uri; + private final UriComponents uri; // ------------------------------------------------------------ Constructors - public TunnelRequestEvent(final FilterChainContext suspendedContext, final ProxyServer proxyServer, final URI uri) { + public TunnelRequestEvent(final FilterChainContext suspendedContext, final ProxyServer proxyServer, final UriComponents uri) { this.suspendedContext = suspendedContext; this.proxyServer = proxyServer; this.uri = uri; @@ -55,7 +54,7 @@ public ProxyServer getProxyServer() { return proxyServer; } - public URI getUri() { + public UriComponents getUri() { return uri; } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java index 313770759d..1e090e69ea 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java @@ -57,7 +57,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT final Request req = httpTransactionContext.getRequest(); ProxyServer proxyServer = httpTransactionContext.getProvider().getClientConfig().getProxyServerSelector() - .select(req.getOriginalURI()); + .select(req.getURI()); String principal = proxyServer.getPrincipal(); String password = proxyServer.getPassword(); Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri("/") diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java index 5d914b0f75..a59d23876b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java @@ -19,14 +19,12 @@ import org.asynchttpclient.providers.grizzly.ConnectionManager; import org.asynchttpclient.providers.grizzly.EventHandler; import org.asynchttpclient.providers.grizzly.HttpTxContext; -import org.asynchttpclient.util.AsyncHttpProviderUtils; +import org.asynchttpclient.uri.UriComponents; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.util.Header; -import java.net.URI; - public final class RedirectHandler implements StatusHandler { public static final RedirectHandler INSTANCE = new RedirectHandler(); @@ -46,17 +44,17 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT throw new IllegalStateException("redirect received, but no location header was present"); } - URI orig; + UriComponents orig; if (httpTransactionContext.getLastRedirectURI() == null) { orig = httpTransactionContext.getRequest().getURI(); } else { - orig = AsyncHttpProviderUtils.getRedirectUri(httpTransactionContext.getRequest().getURI(), + orig = UriComponents.create(httpTransactionContext.getRequest().getURI(), httpTransactionContext.getLastRedirectURI()); } httpTransactionContext.setLastRedirectURI(redirectURL); Request requestToSend; - URI uri = AsyncHttpProviderUtils.getRedirectUri(orig, redirectURL); - if (!uri.toString().equalsIgnoreCase(orig.toString())) { + UriComponents uri = UriComponents.create(orig, redirectURL); + if (!uri.toUrl().equalsIgnoreCase(orig.toUrl())) { requestToSend = EventHandler.newRequest(uri, responsePacket, httpTransactionContext, sendAsGet(responsePacket, httpTransactionContext)); } else { diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index d3b796fc0e..301308ddcc 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java @@ -90,7 +90,7 @@ public void testNoTransferEncoding() throws Exception { .setConnectionTimeoutInMs(15000) .setRequestTimeoutInMs(15000) .setAllowPoolingConnection(false) - .setUseRawUrl(true) + .setDisableUrlEncodingForBoundRequests(true) .setIOThreadMultiplier(2) // 2 is default .build(); diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index d6abb3a8ef..bc9e908b63 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,7 +39,7 @@ io.netty netty-all - 4.0.21.Final + 4.0.20.Final org.javassist diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 0045be2233..f17d81a80c 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -32,6 +32,7 @@ import org.asynchttpclient.providers.netty.handler.Processor; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.SslUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,7 +64,6 @@ import java.io.IOException; import java.lang.reflect.Field; -import java.net.URI; import java.security.GeneralSecurityException; import java.util.HashMap; import java.util.Map; @@ -296,7 +296,7 @@ protected void initChannel(Channel ch) throws Exception { }); } - public Bootstrap getBootstrap(URI uri, boolean useSSl, boolean useProxy) { + public Bootstrap getBootstrap(UriComponents uri, boolean useSSl, boolean useProxy) { return (uri.getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); } @@ -374,7 +374,7 @@ public static void upgradePipelineForWebSockets(Channel channel) { channel.pipeline().addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); } - public Channel pollAndVerifyCachedChannel(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { final Channel channel = channelPool.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); if (channel != null) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 06f1d538e4..2d60a7443f 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -27,6 +27,7 @@ import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; +import org.asynchttpclient.uri.UriComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +36,6 @@ import io.netty.handler.codec.http.HttpResponse; import java.net.SocketAddress; -import java.net.URI; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -88,7 +88,7 @@ public enum STATE { // state mutated only inside the event loop private Channel channel; - private URI uri; + private UriComponents uri; private boolean keepAlive = true; private Request request; private NettyRequest nettyRequest; @@ -101,7 +101,7 @@ public enum STATE { private boolean dontWriteBodyBecauseExpectContinue; private boolean allowConnect; - public NettyResponseFuture(URI uri,// + public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// NettyRequest nettyRequest,// @@ -121,11 +121,11 @@ public NettyResponseFuture(URI uri,// maxRetry = Integer.getInteger(MAX_RETRY, config.getMaxRequestRetry()); } - public URI getURI() { + public UriComponents getURI() { return uri; } - public void setURI(URI uri) { + public void setURI(UriComponents uri) { this.uri = uri; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 436d16ea3f..bb52ccf29a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -45,6 +45,7 @@ import org.asynchttpclient.providers.netty.response.ResponseHeaders; import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +60,6 @@ import io.netty.handler.codec.http.LastHttpContent; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.List; final class HttpProtocol extends Protocol { @@ -80,8 +78,8 @@ private Realm.RealmBuilder newRealmBuilder(Realm realm) { 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 ? uri.getHost() : request.getVirtualHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { String challengeHeader = SpnegoEngine.instance().generateToken(server); @@ -89,7 +87,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); return newRealmBuilder(realm)// - .setUri(uri.getRawPath())// + .setUri(uri.getPath())// .setMethodName(request.getMethod())// .setScheme(Realm.AuthScheme.KERBEROS)// .build(); @@ -124,12 +122,12 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); - URI uri = request.getURI(); + UriComponents uri = request.getURI(); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); future.getAndSetAuth(false); return newRealmBuilder(realm)// .setScheme(realm.getAuthScheme())// - .setUri(uri.getRawPath())// + .setUri(uri.getPath())// .setMethodName(request.getMethod())// .setNtlmMessageType2Received(true)// .build(); @@ -192,7 +190,7 @@ private final boolean updateBodyAndInterrupt(NettyResponseFuture future, Asyn return state; } - private void markAsDone(NettyResponseFuture future, final Channel channel) throws MalformedURLException { + 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 { @@ -207,15 +205,10 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) th } } - private final String computeRealmURI(Realm realm, URI requestURI) throws URISyntaxException { + private final String computeRealmURI(Realm realm, UriComponents requestURI) { if (realm.isUseAbsoluteURI()) { if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { - return new URI( - requestURI.getScheme(), - requestURI.getAuthority(), - requestURI.getPath(), - null, - null).toString(); + return requestURI.withNewQuery(null).toString(); } else { return requestURI.toString(); } @@ -346,11 +339,11 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques } try { - URI requestURI = request.getURI(); + UriComponents requestURI = request.getURI(); String scheme = requestURI.getScheme(); LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - String host = AsyncHttpProviderUtils.getHost(requestURI); - int port = AsyncHttpProviderUtils.getPort(requestURI); + String host = requestURI.getHost(); + int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); channels.upgradeProtocol(channel.pipeline(), scheme, host, port); } catch (Throwable ex) { @@ -388,7 +381,7 @@ private boolean handleResponseAndExit(final Channel channel, final NettyResponse int statusCode = response.getStatus().code(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response.headers()); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); return handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)// || handleUnauthorizedAndExit(statusCode, realm, request, response, future, proxyServer, channel)// @@ -438,7 +431,7 @@ && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest() LastHttpContent lastChunk = (LastHttpContent) chunk; HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); if (!trailingHeaders.isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), future.getHttpHeaders(), trailingHeaders); + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 7f9032cb9a..0c482212df 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -37,6 +37,7 @@ import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,7 +48,8 @@ import io.netty.handler.codec.http.HttpResponse; import java.io.IOException; -import java.net.URI; +import java.util.HashSet; +import java.util.Set; public abstract class Protocol { @@ -62,6 +64,15 @@ public abstract class Protocol { protected final boolean hasIOExceptionFilters; private final TimeConverter timeConverter; + public static final Set REDIRECT_STATUSES = new HashSet(); + + static { + REDIRECT_STATUSES.add(MOVED_PERMANENTLY); + REDIRECT_STATUSES.add(FOUND); + REDIRECT_STATUSES.add(SEE_OTHER); + REDIRECT_STATUSES.add(TEMPORARY_REDIRECT); + } + public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { this.channels = channels; @@ -84,11 +95,8 @@ protected boolean handleRedirectAndExit(Request request, NettyResponseFuture throws Exception { io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); - boolean redirectEnabled = request.isRedirectOverrideSet() ? request.isRedirectEnabled() : config.isRedirectEnabled(); - boolean isRedirectStatus = status.equals(MOVED_PERMANENTLY) || status.equals(FOUND) || status.equals(SEE_OTHER) - || status.equals(TEMPORARY_REDIRECT); - if (redirectEnabled && isRedirectStatus) { + if (AsyncHttpProviderUtils.followRedirect(config, request) && REDIRECT_STATUSES.contains(status)) { if (future.incrementAndGetCurrentRedirectCount() >= config.getMaxRedirects()) { throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); @@ -97,13 +105,13 @@ protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future.getAndSetAuth(false); String location = response.headers().get(HttpHeaders.Names.LOCATION); - URI uri = AsyncHttpProviderUtils.getRedirectUri(future.getURI(), location); + UriComponents uri = UriComponents.create(future.getURI(), location); - if (!uri.toString().equals(future.getURI().toString())) { + if (!uri.equals(future.getURI())) { final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); - if (config.isRemoveQueryParamOnRedirect()) { - requestBuilder.setQueryParameters(null); - } + + if (!config.isRemoveQueryParamOnRedirect()) + requestBuilder.addQueryParams(future.getRequest().getQueryParams()); // FIXME why not do that for 301 and 307 too? // FIXME I think condition is wrong diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 459643fe45..5aa2ce0663 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -80,7 +80,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config); - HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response.headers()); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); if (handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)) { return; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 77fda9c612..a0dfad4bad 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -20,9 +20,22 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map.Entry; import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.FluentStringsMap; +import org.asynchttpclient.Param; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; import org.asynchttpclient.Request; @@ -41,25 +54,11 @@ import org.asynchttpclient.providers.netty.request.body.NettyMultipartBody; import org.asynchttpclient.providers.netty.ws.WebSocketUtil; import org.asynchttpclient.spnego.SpnegoEngine; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.util.AuthenticatorUtils; import org.asynchttpclient.util.UTF8UrlEncoder; -import io.netty.buffer.Unpooled; -import io.netty.handler.codec.http.DefaultFullHttpRequest; -import io.netty.handler.codec.http.DefaultHttpRequest; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpVersion; - -import java.io.IOException; -import java.net.URI; -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; @@ -72,25 +71,25 @@ public NettyRequestFactory(AsyncHttpClientConfig config, NettyAsyncHttpProviderC this.nettyConfig = nettyConfig; } - private String requestUri(URI uri, ProxyServer proxyServer, HttpMethod method) { + private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod method) { if (method == HttpMethod.CONNECT) return AsyncHttpProviderUtils.getAuthority(uri); else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) return uri.toString(); - else if (uri.getRawQuery() != null) - return uri.getRawPath() + "?" + uri.getRawQuery(); + else if (uri.getQuery() != null) + return uri.getPath() + "?" + uri.getQuery(); else - return uri.getRawPath(); + return uri.getPath(); } - private String hostHeader(Request request, URI uri, Realm realm) { + private String hostHeader(Request request, UriComponents uri, Realm realm) { String hostHeader = null; - String host = request.getVirtualHost() != null ? request.getVirtualHost() : AsyncHttpProviderUtils.getHost(uri); + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); if (host != null) { if (request.getVirtualHost() != null || uri.getPort() == -1) @@ -102,7 +101,7 @@ private String hostHeader(Request request, URI uri, Realm realm) { return hostHeader; } - private String authorizationHeader(Request request, URI uri, ProxyServer proxyServer, Realm realm) throws IOException { + private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { String authorizationHeader = null; @@ -144,7 +143,7 @@ private String authorizationHeader(Request request, URI uri, ProxyServer proxySe else if (request.getVirtualHost() != null) host = request.getVirtualHost(); else - host = AsyncHttpProviderUtils.getHost(uri); + host = uri.getHost(); if (host == null) host = "127.0.0.1"; @@ -196,17 +195,14 @@ private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer return proxyAuthorization; } - private byte[] computeBodyFromParams(FluentStringsMap params, Charset bodyCharset) { + private byte[] computeBodyFromParams(List params, Charset bodyCharset) { StringBuilder sb = new StringBuilder(); - for (Entry> paramEntry : params) { - String key = paramEntry.getKey(); - for (String value : paramEntry.getValue()) { - UTF8UrlEncoder.appendEncoded(sb, key); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); - sb.append("&"); - } + 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); @@ -227,15 +223,15 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { } else if (request.getStreamData() != null) { nettyBody = new NettyInputStreamBody(request.getStreamData()); - } else if (isNonEmpty(request.getParams())) { + } 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.getParams(), bodyCharset), contentType); + nettyBody = new NettyByteArrayBody(computeBodyFromParams(request.getFormParams(), bodyCharset), contentType); - } else if (request.getParts() != null) { + } else if (isNonEmpty(request.getParts())) { nettyBody = new NettyMultipartBody(request.getParts(), request.getHeaders(), nettyConfig); } else if (request.getFile() != null) { @@ -257,7 +253,7 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { return nettyBody; } - public NettyRequest newNettyRequest(Request request, URI uri, boolean forceConnect, ProxyServer proxyServer) throws IOException { + 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; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 48d6cfb3de..2fdaab8d50 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -36,6 +36,7 @@ import org.asynchttpclient.providers.netty.request.timeout.IdleConnectionTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.util.ProxyUtils; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; @@ -52,7 +53,6 @@ import java.io.IOException; import java.net.InetSocketAddress; -import java.net.URI; import java.util.Map; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; @@ -147,7 +147,7 @@ private final boolean validateWebSocketRequest(Request request, AsyncHandler return request.getMethod().equals(HttpMethod.GET.name()) && asyncHandler instanceof WebSocketUpgradeHandler; } - private Channel getCachedChannel(NettyResponseFuture future, URI uri, ConnectionPoolKeyStrategy poolKeyGen, ProxyServer proxyServer) { + private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, ProxyServer proxyServer) { if (future != null && future.reuseChannel() && isChannelValid(future.channel())) return future.channel(); @@ -155,7 +155,7 @@ private Channel getCachedChannel(NettyResponseFuture future, URI uri, Connect return channels.pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); } - private ListenableFuture sendRequestWithCachedChannel(Request request, URI uri, ProxyServer proxy, + private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { future.setState(NettyResponseFuture.STATE.POOLED); @@ -185,18 +185,18 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, UR return future; } - private InetSocketAddress remoteAddress(Request request, URI uri, ProxyServer proxy, boolean useProxy) { + private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { if (request.getInetAddress() != null) - return new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getPort(uri)); + return new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); else if (!useProxy || ProxyUtils.avoidProxy(proxy, uri.getHost())) - return new InetSocketAddress(AsyncHttpProviderUtils.getHost(uri), AsyncHttpProviderUtils.getPort(uri)); + return new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); else return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - private ChannelFuture connect(Request request, URI uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { + private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); if (request.getLocalAddress() != null) @@ -207,7 +207,7 @@ private ChannelFuture connect(Request request, URI uri, ProxyServer proxy, boole private ListenableFuture sendRequestWithNewChannel(// Request request,// - URI uri,// + UriComponents uri,// ProxyServer proxy,// boolean useProxy,// NettyResponseFuture future,// @@ -249,7 +249,7 @@ private ListenableFuture sendRequestWithNewChannel(// return connectListener.future(); } - private NettyResponseFuture newNettyResponseFuture(URI uri, Request request, AsyncHandler asyncHandler, + private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); @@ -271,7 +271,7 @@ private NettyResponseFuture newNettyResponseFuture(URI uri, Request reque } private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, - NettyResponseFuture originalFuture, URI uri, ProxyServer proxy, boolean forceConnect) throws IOException { + NettyResponseFuture originalFuture, UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); @@ -293,7 +293,7 @@ private ListenableFuture sendRequestThroughSslProxy(// AsyncHandler asyncHandler,// NettyResponseFuture future,// boolean reclaimCache,// - URI uri,// + UriComponents uri,// ProxyServer proxyServer) throws IOException { // Using CONNECT depends on wither we can fetch a valid channel or not @@ -323,7 +323,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// AsyncHandler asyncHandler,// NettyResponseFuture future,// boolean reclaimCache,// - URI uri,// + UriComponents uri,// ProxyServer proxyServer,// boolean useProxy,// boolean forceConnect) throws IOException { @@ -353,7 +353,7 @@ public ListenableFuture sendRequest(final Request request,// throw new IOException("WebSocket method must be a GET"); } - URI uri = config.isUseRawUrl() ? request.getRawURI() : request.getURI(); + UriComponents uri = request.getURI(); ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); boolean resultOfAConnect = future != null && future.getNettyRequest() != null && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java index 8f08d5f08e..5f9f56da92 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java @@ -15,14 +15,13 @@ */ package org.asynchttpclient.providers.netty.response; -import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.HttpResponseHeaders; - import io.netty.handler.codec.http.HttpHeaders; -import java.net.URI; import java.util.Map; +import org.asynchttpclient.FluentCaseInsensitiveStringsMap; +import org.asynchttpclient.HttpResponseHeaders; + /** * A class that represent the HTTP headers. */ @@ -33,11 +32,11 @@ public class ResponseHeaders extends HttpResponseHeaders { private final FluentCaseInsensitiveStringsMap headers; // FIXME unused AsyncHttpProvider provider - public ResponseHeaders(URI uri, HttpHeaders responseHeaders) { - this(uri, responseHeaders, null); + public ResponseHeaders(HttpHeaders responseHeaders) { + this(responseHeaders, null); } - public ResponseHeaders(URI uri, HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { + public ResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { super(traillingHeaders != null); this.responseHeaders = responseHeaders; this.trailingHeaders = traillingHeaders; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java index 43d3f8a0e1..996038de10 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java @@ -21,10 +21,10 @@ import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.Response; +import org.asynchttpclient.uri.UriComponents; import io.netty.handler.codec.http.HttpResponse; -import java.net.URI; import java.util.List; /** @@ -34,7 +34,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(URI uri, HttpResponse response, AsyncHttpClientConfig config) { + public ResponseStatus(UriComponents uri, HttpResponse response, AsyncHttpClientConfig config) { super(uri, config); this.response = response; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java index 57b99ae2a5..c94ed864ad 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java @@ -14,9 +14,10 @@ import static org.asynchttpclient.util.MiscUtil.isNonEmpty; -import java.net.URI; import java.util.List; +import org.asynchttpclient.uri.UriComponents; + public final class HttpUtil { public static final String HTTPS = "https"; @@ -39,7 +40,7 @@ public static boolean isSecure(String scheme) { return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); } - public static boolean isSecure(URI uri) { + public static boolean isSecure(UriComponents uri) { return isSecure(uri.getScheme()); } } diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyFilterTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyFilterTest.java index d1c6fd0ebb..f725ea2288 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyFilterTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyFilterTest.java @@ -15,7 +15,9 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.async.FilterTest; +import org.testng.annotations.Test; +@Test public class NettyFilterTest extends FilterTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java index de5fbc896e..7c29f993e3 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java @@ -70,9 +70,9 @@ protected String getTargetUrl() { private ListenableFuture testMethodRequest(AsyncHttpClient client, int requests, String action, String id) throws IOException { Request r = new RequestBuilder("GET")// .setUrl(getTargetUrl())// - .addQueryParameter(action, "1")// - .addQueryParameter("maxRequests", "" + requests)// - .addQueryParameter("id", id)// + .addQueryParam(action, "1")// + .addQueryParam("maxRequests", "" + requests)// + .addQueryParam("id", id)// .build(); return client.executeRequest(r); } From aa79b4c8e1accc6fe6af60bc4549028cf69cca47 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 00:33:16 +0200 Subject: [PATCH 0120/2070] Rename Realm.domain, close #593 --- api/src/main/java/org/asynchttpclient/Realm.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 3214651fac..765896b5ca 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -48,7 +48,7 @@ public class Realm { private final String enc; private final String host; private final boolean messageType2Received; - private final String domain; + private final String ntlmDomain; private final Charset charset; private final boolean useAbsoluteURI; private final boolean omitQuery; @@ -58,7 +58,7 @@ public enum AuthScheme { } private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, - String qop, String nc, String cnonce, String uri, String method, boolean usePreemptiveAuth, String domain, String enc, + String qop, String nc, String cnonce, String uri, String method, boolean usePreemptiveAuth, String ntlmDomain, String enc, String host, boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery) { this.principal = principal; @@ -75,7 +75,7 @@ private Realm(AuthScheme scheme, String principal, String password, String realm this.uri = uri; this.methodName = method; this.usePreemptiveAuth = usePreemptiveAuth; - this.domain = domain; + this.ntlmDomain = ntlmDomain; this.enc = enc; this.host = host; this.messageType2Received = messageType2Received; @@ -164,7 +164,7 @@ public boolean getUsePreemptiveAuth() { * @return the NTLM domain */ public String getNtlmDomain() { - return domain; + return ntlmDomain; } /** From 7e78f67a28593b5f602093b23c44db350fbc79ab Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 00:56:15 +0200 Subject: [PATCH 0121/2070] Use followRedirect everywhere, close #604 --- .../org/asynchttpclient/AsyncHttpClientConfig.java | 2 +- .../java/org/asynchttpclient/RequestBuilder.java | 4 ++-- .../java/org/asynchttpclient/RequestBuilderBase.java | 10 +++++----- .../org/asynchttpclient/SimpleAsyncHttpClient.java | 6 +++--- .../async/AsyncProvidersBasicTest.java | 2 +- .../async/AsyncStreamHandlerTest.java | 2 +- .../org/asynchttpclient/async/BasicAuthTest.java | 2 +- .../java/org/asynchttpclient/async/ChunkingTest.java | 2 +- .../asynchttpclient/async/FollowingThreadTest.java | 2 +- .../async/HttpToHttpsRedirectTest.java | 6 +++--- .../asynchttpclient/async/MultipartUploadTest.java | 2 +- .../asynchttpclient/async/NoNullResponseTest.java | 2 +- .../async/PerRequestRelative302Test.java | 10 +++++----- .../asynchttpclient/async/PostRedirectGetTest.java | 4 ++-- .../asynchttpclient/async/ProxyTunnellingTest.java | 6 +++--- .../async/RedirectConnectionUsageTest.java | 2 +- .../org/asynchttpclient/async/Relative302Test.java | 8 ++++---- .../org/asynchttpclient/async/RemoteSiteTest.java | 12 ++++++------ .../org/asynchttpclient/websocket/RedirectTest.java | 2 +- .../grizzly/GrizzlyNoTransferEncodingTest.java | 2 +- 20 files changed, 44 insertions(+), 44 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 65fac8d2be..11b2cbe28d 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -676,7 +676,7 @@ public Builder setRequestTimeoutInMs(int requestTimeoutInMs) { * @param redirectEnabled true if enabled. * @return a {@link Builder} */ - public Builder setFollowRedirects(boolean followRedirect) { + public Builder setFollowRedirect(boolean followRedirect) { this.followRedirect = followRedirect; return this; } diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilder.java b/api/src/main/java/org/asynchttpclient/RequestBuilder.java index 52fef5a98a..b5d2e91444 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilder.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilder.java @@ -165,8 +165,8 @@ public RequestBuilder setVirtualHost(String virtualHost) { } @Override - public RequestBuilder setFollowRedirects(boolean followRedirects) { - return super.setFollowRedirects(followRedirects); + public RequestBuilder setFollowRedirect(boolean followRedirect) { + return super.setFollowRedirect(followRedirect); } @Override diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index cd38530ac2..3e0457c862 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -62,7 +62,7 @@ private static final class RequestImpl implements Request { public ProxyServer proxyServer; private Realm realm; private File file; - private Boolean followRedirects; + private Boolean followRedirect; private int requestTimeoutInMs; private long rangeOffset; public String charset; @@ -91,7 +91,7 @@ public RequestImpl(Request prototype) { this.proxyServer = prototype.getProxyServer(); this.realm = prototype.getRealm(); this.file = prototype.getFile(); - this.followRedirects = prototype.getFollowRedirect(); + this.followRedirect = prototype.getFollowRedirect(); this.requestTimeoutInMs = prototype.getRequestTimeoutInMs(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); @@ -200,7 +200,7 @@ public File getFile() { @Override public Boolean getFollowRedirect() { - return followRedirects; + return followRedirect; } @Override @@ -527,8 +527,8 @@ public T setRealm(Realm realm) { return derived.cast(this); } - public T setFollowRedirects(boolean followRedirects) { - request.followRedirects = followRedirects; + public T setFollowRedirect(boolean followRedirect) { + request.followRedirect = followRedirect; return derived.cast(this); } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 3ea5d1e72c..6dc6036fa3 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -373,7 +373,7 @@ public enum ErrorDocumentBehaviour { */ public interface DerivedBuilder { - DerivedBuilder setFollowRedirects(boolean followRedirects); + DerivedBuilder setFollowRedirect(boolean followRedirect); DerivedBuilder setVirtualHost(String virtualHost); @@ -494,8 +494,8 @@ public Builder setVirtualHost(String virtualHost) { return this; } - public Builder setFollowRedirects(boolean followRedirects) { - requestBuilder.setFollowRedirects(followRedirects); + public Builder setFollowRedirect(boolean followRedirect) { + requestBuilder.setFollowRedirect(followRedirect); return this; } diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 2a17d861d5..4e2906eea4 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -1339,7 +1339,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetMaxRedirectTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaxRedirects(0).setFollowRedirects(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); diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 985b077695..835bdf31be 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -370,7 +370,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/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index bb388d908e..2c0c3c553c 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -197,7 +197,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().setFollowRedirects(true).setMaxRedirects(10).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaxRedirects(10).build()); try { Future f = client.prepareGet(getTargetUrl2())// .setRealm((new Realm.RealmBuilder()).setPrincipal(USER).setPassword(ADMIN).build())// diff --git a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java index c590a94a3c..8d8845faa7 100644 --- a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java @@ -50,7 +50,7 @@ public void testCustomChunking() throws Exception { bc.setMaxConnectionsTotal(1); bc.setConnectionTimeoutInMs(1000); bc.setRequestTimeoutInMs(1000); - bc.setFollowRedirects(true); + bc.setFollowRedirect(true); AsyncHttpClient c = getAsyncHttpClient(bc.build()); try { diff --git a/api/src/test/java/org/asynchttpclient/async/FollowingThreadTest.java b/api/src/test/java/org/asynchttpclient/async/FollowingThreadTest.java index 5ccb8ff6c8..2897d772e3 100644 --- a/api/src/test/java/org/asynchttpclient/async/FollowingThreadTest.java +++ b/api/src/test/java/org/asynchttpclient/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/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java index 132c87f453..f186cbb3dd 100644 --- a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java @@ -98,7 +98,7 @@ public void httpToHttpsRedirect() throws Exception { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// .setMaxRedirects(5)// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); AsyncHttpClient c = getAsyncHttpClient(cg); @@ -118,7 +118,7 @@ public void httpToHttpsProperConfig() throws Exception { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// .setMaxRedirects(5)// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); AsyncHttpClient c = getAsyncHttpClient(cg); @@ -144,7 +144,7 @@ public void relativeLocationUrl() throws Exception { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// .setMaxRedirects(5)// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); AsyncHttpClient c = getAsyncHttpClient(cg); diff --git a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java index cbf13877de..1222e4408d 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java @@ -166,7 +166,7 @@ public void testSendingSmallFilesAndByteArray() { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); - bc.setFollowRedirects(true); + bc.setFollowRedirect(true); AsyncHttpClient c = getAsyncHttpClient(bc.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 2b78e7972a..0e27a0fb86 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -56,7 +56,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Exception { } 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).setMaxConnectionsPerHost(-1).setMaxConnectionsTotal(-1); return getAsyncHttpClient(configBuilder.build()); } diff --git a/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java index 90e99a4567..76450d53c2 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestRelative302Test.java @@ -94,7 +94,7 @@ public void redirected302Test() throws Exception { isSet.getAndSet(false); AsyncHttpClient c = getAsyncHttpClient(null); try { - Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); + Response response = c.prepareGet(getTargetUrl()).setFollowRedirect(true).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -111,10 +111,10 @@ public void redirected302Test() throws Exception { // @Test(groups = { "online", "default_provider" }) public void notRedirected302Test() throws Exception { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { - Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(false).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); + Response response = c.prepareGet(getTargetUrl()).setFollowRedirect(false).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 302); @@ -146,7 +146,7 @@ public void redirected302InvalidTest() throws Exception { AsyncHttpClient c = getAsyncHttpClient(null); try { // If the test hit a proxy, no ConnectException will be thrown and instead of 404 will be returned. - Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)).execute().get(); + Response response = c.preparePost(getTargetUrl()).setFollowRedirect(true).setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 404); @@ -163,7 +163,7 @@ public void relativeLocationUrl() throws Exception { AsyncHttpClient c = getAsyncHttpClient(null); try { - Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "/foo/test").execute().get(); + Response response = c.preparePost(getTargetUrl()).setFollowRedirect(true).setHeader("X-redirect", "/foo/test").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 302); assertEquals(response.getUri().toString(), getTargetUrl()); diff --git a/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java index 80865b5e6b..306db3efed 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PostRedirectGetTest.java @@ -75,7 +75,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() { @Override public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect @@ -110,7 +110,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() { @Override public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect diff --git a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java index 01d85ac608..203f52a26b 100644 --- a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java @@ -78,7 +78,7 @@ public void testRequestProxy() throws IOException, InterruptedException, Executi ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); @@ -108,7 +108,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }) public void testConfigProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setProxyServer(new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1))// .setAcceptAnyCertificate(true)// .build(); @@ -142,7 +142,7 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, .setProxyProtocol(ProxyServer.Protocol.HTTPS)// .setProxyHost("127.0.0.1")// .setProxyPort(port1)// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .setUrl(getTargetUrl2())// .setAcceptAnyCertificate(true)// .setHeader("Content-Type", "text/html")// diff --git a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java index 6849615298..8241e49f4d 100644 --- a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java @@ -79,7 +79,7 @@ public void testGetRedirectFinalUrl() throws Exception { .setMaxConnectionsTotal(1)// .setConnectionTimeoutInMs(1000)// .setRequestTimeoutInMs(1000)// - .setFollowRedirects(true)// + .setFollowRedirect(true)// .build(); AsyncHttpClient c = getAsyncHttpClient(config); diff --git a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java index 56fac7b88b..081ddd1e0a 100644 --- a/api/src/test/java/org/asynchttpclient/async/Relative302Test.java +++ b/api/src/test/java/org/asynchttpclient/async/Relative302Test.java @@ -90,7 +90,7 @@ public void testAllSequentiallyBecauseNotThreadSafe() throws Exception { // @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Exception { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { @@ -110,7 +110,7 @@ public void redirected302Test() throws Exception { // @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Exception { 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. @@ -130,7 +130,7 @@ public void redirected302InvalidTest() throws Exception { public void absolutePathRedirectTest() throws Exception { 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"; @@ -151,7 +151,7 @@ public void absolutePathRedirectTest() throws Exception { public void relativePathRedirectTest() throws Exception { 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/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index d03c666900..36a735b610 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -127,7 +127,7 @@ public void testGoogleComWithTimeout() throws Exception { @Test(groups = { "online", "default_provider" }) public void asyncStatusHEADContentLenghtTest() throws Exception { - 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(); @@ -154,7 +154,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Exception { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirects(true) + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirect(true) .setAllowPoolingConnection(false).setMaxRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); @@ -219,7 +219,7 @@ public void testAHC60() throws Exception { @Test(groups = { "online", "default_provider" }) public void stripQueryStringTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); @@ -234,7 +234,7 @@ public void stripQueryStringTest() throws Exception { @Test(groups = { "online", "default_provider" }) public void stripQueryStringNegativeTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirects(true) + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirect(true) .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { @@ -252,7 +252,7 @@ public void evilCoookieTest() throws Exception { AsyncHttpClient c = getAsyncHttpClient(null); try { RequestBuilder builder2 = new RequestBuilder("GET"); - builder2.setFollowRedirects(true); + builder2.setFollowRedirect(true); builder2.setUrl("http://www.google.com/"); builder2.addHeader("Content-Type", "text/plain"); builder2.addCookie(new Cookie("evilcookie", "test", "test", ".google.com", "/", -1L, 10, false, false)); @@ -268,7 +268,7 @@ public void evilCoookieTest() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void testAHC62Com() throws Exception { - 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/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java b/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java index c0a6c2fc55..b0b825fa86 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/RedirectTest.java @@ -76,7 +76,7 @@ public void configure(WebSocketServletFactory factory) { @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(""); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index 301308ddcc..8655f47753 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/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) From b0056567b1dcad3faea7a02686bee8f32004fc67 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 15:35:08 +0200 Subject: [PATCH 0122/2070] Rename getAllowPoolingConnection into isAllowPoolingConnection, close #605 --- .../java/org/asynchttpclient/AsyncHttpClientConfig.java | 6 +++--- .../org/asynchttpclient/util/AsyncHttpProviderUtils.java | 2 +- .../asynchttpclient/providers/netty/channel/Channels.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 11b2cbe28d..8c8a4ba980 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -280,7 +280,7 @@ public int getMaxRedirects() { * * @return true if keep-alive is enabled */ - public boolean getAllowPoolingConnection() { + public boolean isAllowPoolingConnection() { return allowPoolingConnection; } @@ -1097,7 +1097,7 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { * @param prototype the configuration to use as a prototype. */ public Builder(AsyncHttpClientConfig prototype) { - allowPoolingConnection = prototype.getAllowPoolingConnection(); + allowPoolingConnection = prototype.isAllowPoolingConnection(); providerConfig = prototype.getAsyncHttpProviderConfig(); connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); @@ -1127,7 +1127,7 @@ public Builder(AsyncHttpClientConfig prototype) { disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); - allowSslConnectionPool = prototype.getAllowPoolingConnection(); + allowSslConnectionPool = prototype.isAllowPoolingConnection(); removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 3e95e67ea6..1fe0aa5521 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -145,7 +145,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) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index f17d81a80c..34f9338bf7 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -147,7 +147,7 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig ChannelPool cp = nettyProviderConfig.getChannelPool(); if (cp == null) { - if (config.getAllowPoolingConnection()) { + if (config.isAllowPoolingConnection()) { cp = new DefaultChannelPool(config, nettyTimer); } else { cp = new NonChannelPool(); From 140296f1ee47286fb84f6e4814cbc31afcbb58cb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:48:14 +0200 Subject: [PATCH 0123/2070] Clean up --- .../AsyncHttpClientConfigDefaults.java | 2 +- .../FluentCaseInsensitiveStringsMap.java | 2 +- .../org/asynchttpclient/FluentStringsMap.java | 2 +- .../main/java/org/asynchttpclient/Realm.java | 2 +- .../asynchttpclient/RequestBuilderBase.java | 2 +- .../multipart/MultipartUtils.java | 2 +- .../oauth/OAuthSignatureCalculator.java | 2 +- .../providers/ResponseBase.java | 2 +- .../util/AsyncHttpProviderUtils.java | 2 +- .../util/AuthenticatorUtils.java | 2 +- .../org/asynchttpclient/util/DateUtil.java | 228 ------------------ .../org/asynchttpclient/util/DateUtils.java | 23 ++ .../util/{MiscUtil.java => MiscUtils.java} | 4 +- .../org/asynchttpclient/util/ProxyUtils.java | 2 +- .../asynchttpclient/util/QueryComputer.java | 2 +- .../async/AsyncProvidersBasicTest.java | 2 +- .../async/ParamEncodingTest.java | 2 +- .../async/PerRequestTimeoutTest.java | 2 +- .../asynchttpclient/async/PostWithQSTest.java | 2 +- .../async/QueryParametersTest.java | 2 +- .../providers/grizzly/GrizzlyResponse.java | 2 +- .../bodyhandler/ParamsBodyHandler.java | 2 +- .../grizzly/bodyhandler/PartsBodyHandler.java | 2 +- .../filters/AsyncHttpClientFilter.java | 2 +- .../websocket/GrizzlyWebSocketAdapter.java | 2 +- .../netty/channel/DefaultChannelPool.java | 2 +- .../netty/future/NettyResponseFuture.java | 2 +- .../providers/netty/handler/HttpProtocol.java | 2 +- .../netty/request/NettyRequestFactory.java | 2 +- .../IdleConnectionTimeoutTimerTask.java | 2 +- .../timeout/RequestTimeoutTimerTask.java | 2 +- .../netty/response/NettyResponse.java | 6 +- .../providers/netty/util/HttpUtil.java | 2 +- 33 files changed, 57 insertions(+), 262 deletions(-) delete mode 100644 api/src/main/java/org/asynchttpclient/util/DateUtil.java create mode 100644 api/src/main/java/org/asynchttpclient/util/DateUtils.java rename api/src/main/java/org/asynchttpclient/util/{MiscUtil.java => MiscUtils.java} (97%) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 4de9e2fcb6..fa05cec469 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.getBoolean; +import static org.asynchttpclient.util.MiscUtils.getBoolean; import org.asynchttpclient.util.DefaultHostnameVerifier; diff --git a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java index 0b9b1ad192..1cbe5baa58 100644 --- a/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/FluentCaseInsensitiveStringsMap.java @@ -16,7 +16,7 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import java.util.ArrayList; import java.util.Arrays; diff --git a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java index b295b7a1be..3e3c45f06e 100644 --- a/api/src/main/java/org/asynchttpclient/FluentStringsMap.java +++ b/api/src/main/java/org/asynchttpclient/FluentStringsMap.java @@ -16,7 +16,7 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import java.util.ArrayList; import java.util.Arrays; diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 765896b5ca..45594ad4ec 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -16,7 +16,7 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.util.StandardCharsets; diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 3e0457c862..a303e86f7e 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.multipart.Part; diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index 9abc5b67d6..b546d1f7ba 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java @@ -17,7 +17,7 @@ import static org.asynchttpclient.multipart.Part.CRLF_BYTES; import static org.asynchttpclient.multipart.Part.EXTRA_BYTES; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.util.StandardCharsets; diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java index 5103a8be5b..6d376fa733 100644 --- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java +++ b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java @@ -16,7 +16,7 @@ */ package org.asynchttpclient.oauth; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.Param; import org.asynchttpclient.Request; diff --git a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java index 66b39a2d4b..202a8bc494 100644 --- a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java +++ b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java @@ -1,6 +1,6 @@ package org.asynchttpclient.providers; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.HttpResponseBodyPart; diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 1fe0aa5521..b753ec9c6a 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.util; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index f8957cb443..349b50cf14 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.util; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; diff --git a/api/src/main/java/org/asynchttpclient/util/DateUtil.java b/api/src/main/java/org/asynchttpclient/util/DateUtil.java deleted file mode 100644 index a41ec9deba..0000000000 --- a/api/src/main/java/org/asynchttpclient/util/DateUtil.java +++ /dev/null @@ -1,228 +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 org.asynchttpclient.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 = 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 NullPointerException 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 { - private static final long serialVersionUID = 1L; - - 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/api/src/main/java/org/asynchttpclient/util/DateUtils.java b/api/src/main/java/org/asynchttpclient/util/DateUtils.java new file mode 100644 index 0000000000..c0b2d49c65 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.util; + +public final class DateUtils { + + private DateUtils() { + } + + public static long millisTime() { + return System.nanoTime() / 1000000; + } +} diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java similarity index 97% rename from api/src/main/java/org/asynchttpclient/util/MiscUtil.java rename to api/src/main/java/org/asynchttpclient/util/MiscUtils.java index 3cad6cfd37..db508f8513 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java @@ -15,9 +15,9 @@ import java.util.Collection; import java.util.Map; -public class MiscUtil { +public class MiscUtils { - private MiscUtil() { + private MiscUtils() { } public static boolean isNonEmpty(String string) { diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java index 16fd18207f..b80f5e605e 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.util; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; diff --git a/api/src/main/java/org/asynchttpclient/util/QueryComputer.java b/api/src/main/java/org/asynchttpclient/util/QueryComputer.java index 058c070c0e..1480dd479d 100644 --- a/api/src/main/java/org/asynchttpclient/util/QueryComputer.java +++ b/api/src/main/java/org/asynchttpclient/util/QueryComputer.java @@ -14,7 +14,7 @@ import java.util.List; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.Param; diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 4e2906eea4..2b84c806e7 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -17,7 +17,7 @@ import static org.asynchttpclient.async.util.TestUtils.TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET; import static org.asynchttpclient.async.util.TestUtils.findFreePort; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; diff --git a/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java b/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java index f423831b01..4b5027f9a6 100644 --- a/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ParamEncodingTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; diff --git a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java index b0d2ef76bd..f6cc5764ec 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; diff --git a/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java b/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java index fe8909583a..f5bb672154 100644 --- a/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PostWithQSTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; diff --git a/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java index cfd3b37db4..6bbd6c80ac 100644 --- a/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java +++ b/api/src/test/java/org/asynchttpclient/async/QueryParametersTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.async; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java index e6664c7d7c..a1825f1b59 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyResponse.java @@ -13,7 +13,7 @@ package org.asynchttpclient.providers.grizzly; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java index afe14577ce..47941e1933 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/ParamsBodyHandler.java @@ -13,7 +13,7 @@ package org.asynchttpclient.providers.grizzly.bodyhandler; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.Param; import org.asynchttpclient.Request; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java index 11171d06a7..2c6e506165 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/bodyhandler/PartsBodyHandler.java @@ -13,7 +13,7 @@ package org.asynchttpclient.providers.grizzly.bodyhandler; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.Body; import org.asynchttpclient.Request; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 80db9da2a9..c431bfc7ac 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -18,7 +18,7 @@ import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHandler; diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java index 8374e89ab8..341c91ffda 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyWebSocketAdapter.java @@ -13,7 +13,7 @@ package org.asynchttpclient.providers.grizzly.websocket; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.websocket.WebSocket; import org.asynchttpclient.websocket.WebSocketListener; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 245723ff6e..54308e010a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.providers.netty.channel; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.providers.netty.DiscardEvent; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 2d60a7443f..0af60186d3 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.providers.netty.future; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index bb52ccf29a..3326fde184 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -20,7 +20,7 @@ import static io.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandler.STATE; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index a0dfad4bad..c62cbce5eb 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -19,7 +19,7 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultHttpRequest; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java index 25a9d17dd8..bea473c9d8 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.providers.netty.request.timeout; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 6035974823..13cae2eb43 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.providers.netty.request.timeout; -import static org.asynchttpclient.util.DateUtil.millisTime; +import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java index d3e1f95451..94eb15d70d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java @@ -23,7 +23,7 @@ import org.asynchttpclient.date.TimeConverter; import org.asynchttpclient.providers.ResponseBase; import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.MiscUtil; +import org.asynchttpclient.util.MiscUtils; import io.netty.handler.codec.http.HttpHeaders; @@ -66,11 +66,11 @@ protected List buildCookies() { List setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE2); - if (!MiscUtil.isNonEmpty(setCookieHeaders)) { + if (!MiscUtils.isNonEmpty(setCookieHeaders)) { setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE); } - if (MiscUtil.isNonEmpty(setCookieHeaders)) { + if (MiscUtils.isNonEmpty(setCookieHeaders)) { List cookies = new ArrayList(); for (String value : setCookieHeaders) { Cookie c = CookieDecoder.decode(value, timeConverter); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java index c94ed864ad..906bc7e8eb 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.providers.netty.util; -import static org.asynchttpclient.util.MiscUtil.isNonEmpty; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import java.util.List; From d159274839243f7876db873c94c21d0e8ced21a2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:50:39 +0200 Subject: [PATCH 0124/2070] Remove useless hasHeaders method --- api/src/main/java/org/asynchttpclient/Request.java | 8 -------- .../main/java/org/asynchttpclient/RequestBuilderBase.java | 5 ----- .../providers/grizzly/filters/AsyncHttpClientFilter.java | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index b182b2caf7..7b419385e8 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -191,12 +191,4 @@ public interface Request { String getBodyEncoding(); ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy(); - - /** - * @return return true if request headers have been added, - * otherwise, returns false. - * - * @since 2.0 - */ - boolean hasHeaders(); } diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index a303e86f7e..f00056c7a6 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -223,11 +223,6 @@ public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { return connectionPoolKeyStrategy; } - @Override - public boolean hasHeaders() { - return headers != null && !headers.isEmpty(); - } - @Override public List getQueryParams() { if (queryParams == null) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index c431bfc7ac..4b9d7fdf19 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -481,7 +481,7 @@ private static void convertToUpgradeRequest(final HttpTxContext ctx) { private void addGeneralHeaders(final Request request, final HttpRequestPacket requestPacket) { - if (request.hasHeaders()) { + if (isNonEmpty(request.getHeaders())) { final FluentCaseInsensitiveStringsMap map = request.getHeaders(); for (final Map.Entry> entry : map.entrySet()) { final String headerName = entry.getKey(); From bd8bdbb010fe586e60cb810a96151dbcbcfb435e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:55:50 +0200 Subject: [PATCH 0125/2070] Have SimpleAHCTransferListener receive an UriComponents --- .../SimpleAsyncHttpClient.java | 24 +++++++++---------- .../simple/SimpleAHCTransferListener.java | 21 ++++++++-------- .../async/SimpleAsyncHttpClientTest.java | 21 ++++++++-------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 6dc6036fa3..d601d4d82c 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -18,6 +18,7 @@ import org.asynchttpclient.resumable.ResumableIOExceptionFilter; import org.asynchttpclient.simple.HeaderMap; import org.asynchttpclient.simple.SimpleAHCTransferListener; +import org.asynchttpclient.uri.UriComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -283,7 +284,7 @@ private Future execute(RequestBuilder rb, BodyConsumer bodyConsumer, T Request request = rb.build(); ProgressAsyncHandler handler = new BodyConsumerAsyncHandler(bodyConsumer, throwableHandler, errorDocumentBehaviour, - request.getUrl(), listener); + request.getURI(), listener); if (resumeEnabled && request.getMethod().equals("GET") && bodyConsumer != null && bodyConsumer instanceof ResumableBodyConsumer) { ResumableBodyConsumer fileBodyConsumer = (ResumableBodyConsumer) bodyConsumer; @@ -735,7 +736,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; @@ -744,11 +745,11 @@ private final static class BodyConsumerAsyncHandler extends AsyncCompletionHandl private long total = -1; public BodyConsumerAsyncHandler(BodyConsumer bodyConsumer, ThrowableHandler exceptionHandler, - ErrorDocumentBehaviour errorDocumentBehaviour, String url, SimpleAHCTransferListener listener) { + ErrorDocumentBehaviour errorDocumentBehaviour, UriComponents uri, SimpleAHCTransferListener listener) { this.bodyConsumer = bodyConsumer; this.exceptionHandler = exceptionHandler; this.errorDocumentBehaviour = errorDocumentBehaviour; - this.url = url; + this.uri = uri; this.listener = listener; } @@ -846,13 +847,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()); } } @@ -862,27 +863,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/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java b/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java index 51448ee38e..02702a0421 100644 --- a/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java +++ b/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java @@ -14,6 +14,7 @@ */ import org.asynchttpclient.SimpleAsyncHttpClient; +import org.asynchttpclient.uri.UriComponents; /** * A simple transfer listener for use with the {@link SimpleAsyncHttpClient}. @@ -29,51 +30,51 @@ public interface SimpleAHCTransferListener { /** * This method is called after the connection status is received. * - * @param url the url for the connection. + * @param uri the uri * @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/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index 895144f989..c4aa459a2b 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -27,6 +27,7 @@ import org.asynchttpclient.multipart.ByteArrayPart; import org.asynchttpclient.simple.HeaderMap; import org.asynchttpclient.simple.SimpleAHCTransferListener; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.StandardCharsets; import org.testng.annotations.Test; @@ -176,19 +177,19 @@ 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) { try { assertEquals(statusCode, 200); - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); } catch (Error e) { errors.add(e); throw e; } } - public void onHeaders(String url, HeaderMap headers) { + public void onHeaders(UriComponents uri, HeaderMap headers) { try { - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); assertNotNull(headers); assertTrue(!headers.isEmpty()); assertEquals(headers.getFirstValue("X-Custom"), "custom"); @@ -198,19 +199,19 @@ public void onHeaders(String url, HeaderMap headers) { } } - public void onCompleted(String url, int statusCode, String statusText) { + public void onCompleted(UriComponents uri, int statusCode, String statusText) { try { assertEquals(statusCode, 200); - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); } catch (Error e) { errors.add(e); throw e; } } - public void onBytesSent(String url, long amount, long current, long total) { + public void onBytesSent(UriComponents uri, long amount, long current, long total) { try { - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); // FIXME Netty bug, see https://github.com/netty/netty/issues/1855 // assertEquals(total, MY_MESSAGE.getBytes().length); } catch (Error e) { @@ -219,9 +220,9 @@ public void onBytesSent(String url, long amount, long current, long total) { } } - public void onBytesReceived(String url, long amount, long current, long total) { + public void onBytesReceived(UriComponents uri, long amount, long current, long total) { try { - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); assertEquals(total, -1); } catch (Error e) { errors.add(e); From 6fa9742072a7154a844818911f8de84815afde1e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 18:11:56 +0200 Subject: [PATCH 0126/2070] Don't replace empty path with a / in Request, close #606 --- .../java/org/asynchttpclient/Request.java | 7 ----- .../asynchttpclient/RequestBuilderBase.java | 22 ++------------- .../resumable/ResumableAsyncHandler.java | 2 +- .../asynchttpclient/uri/UriComponents.java | 11 ++++++++ .../util/AsyncHttpProviderUtils.java | 18 ------------- .../async/AsyncProvidersBasicTest.java | 10 +++---- .../async/RequestBuilderTest.java | 10 +++---- .../resumable/ResumableAsyncHandlerTest.java | 4 +-- .../providers/grizzly/HttpTxContext.java | 20 +++++++------- .../filters/AsyncHttpClientFilter.java | 27 +++++++++---------- .../grizzly/filters/ProxyFilter.java | 2 +- .../statushandler/AuthorizationHandler.java | 2 +- .../statushandler/RedirectHandler.java | 2 +- .../providers/netty/handler/HttpProtocol.java | 14 +++++----- .../netty/request/NettyRequestFactory.java | 4 +-- 15 files changed, 61 insertions(+), 94 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 7b419385e8..597931456f 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -46,13 +46,6 @@ public interface Request { */ String getMethod(); - /** - * Return the decoded url - * - * @return the decoded url - */ - String getUrl(); - UriComponents getURI(); /** diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index f00056c7a6..8629599db9 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -114,20 +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; - } - } - - @Override - public String getUrl() { - return removeTrailingSlash(getURI()); - } - @Override public UriComponents getURI() { return uri; @@ -302,8 +288,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); } @@ -602,14 +586,12 @@ 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(// @@ -617,7 +599,7 @@ private void computeFinalUri() { request.uri.getUserInfo(),// request.uri.getHost(),// request.uri.getPort(),// - newPath,// + request.uri.getPath(),// newQuery); } diff --git a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java index c7fd13d75a..f91cdeb313 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java +++ b/api/src/main/java/org/asynchttpclient/resumable/ResumableAsyncHandler.java @@ -197,7 +197,7 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws */ public Request adjustRequestRange(Request request) { - Long ri = resumableIndex.get(request.getUrl()); + Long ri = resumableIndex.get(request.getURI().toUrl()); if (ri != null) { byteTransferred.set(ri); } diff --git a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java index 898557d6a5..5343071e61 100644 --- a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java +++ b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.uri; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; + import java.net.URI; import java.net.URISyntaxException; @@ -64,6 +66,15 @@ public String getQuery() { return query; } + /** + * Convenient for HTTP layer when targeting server root + * + * @return the raw path or "/" if it's null + */ + public String getNonEmptyPath() { + return isNonEmpty(path) ? path : "/"; + } + public String getPath() { return path; } diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index b753ec9c6a..dcd6164c9a 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -12,8 +12,6 @@ */ package org.asynchttpclient.util; -import static org.asynchttpclient.util.MiscUtils.isNonEmpty; - import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.HttpResponseBodyPart; @@ -49,22 +47,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; - } - /** * @param bodyParts NON EMPTY body part * @param maxLen diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 2b84c806e7..d8f8936d33 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -64,12 +64,16 @@ public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { + protected abstract String acceptEncodingHeader(); + + protected abstract AsyncHttpProviderConfig getProviderConfig(); + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncProviderEncodingTest() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "?q=+%20x").build(); - assertEquals(request.getUrl(), getTargetUrl() + "?q=%20%20x"); + assertEquals(request.getURI().toUrl(), getTargetUrl() + "?q=%20%20x"); String url = client.executeRequest(request, new AsyncCompletionHandler() { @Override @@ -680,8 +684,6 @@ public Response onCompleted(Response response) throws Exception { client.close(); } } - - protected abstract String acceptEncodingHeader(); @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBasicGZIPTest() throws Exception { @@ -1595,6 +1597,4 @@ public void mirrorByteTest() throws Exception { client.close(); } } - - protected abstract AsyncHttpProviderConfig getProviderConfig(); } diff --git a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java index fe560de3ac..9086595c99 100644 --- a/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RequestBuilderTest.java @@ -70,7 +70,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); } } @@ -83,7 +83,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"}) @@ -93,7 +93,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")); @@ -104,14 +104,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"}) diff --git a/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java index 5e3cc094aa..196b2e4df6 100644 --- a/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/resumable/ResumableAsyncHandlerTest.java @@ -31,13 +31,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-"); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java index 308558b228..a69dad744b 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/HttpTxContext.java @@ -18,6 +18,7 @@ import org.asynchttpclient.providers.grizzly.bodyhandler.BodyHandler; import org.asynchttpclient.providers.grizzly.statushandler.StatusHandler; import org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.asynchttpclient.websocket.WebSocket; import org.glassfish.grizzly.CloseListener; @@ -33,6 +34,7 @@ import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; + import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.filterchain.FilterChain; @@ -50,7 +52,7 @@ public final class HttpTxContext { private final GrizzlyAsyncHttpProvider provider; private Request request; - private String requestUrl; + private UriComponents requestUri; private final AsyncHandler handler; private BodyHandler bodyHandler; private StatusHandler statusHandler; @@ -61,7 +63,7 @@ public final class HttpTxContext { private final AtomicLong totalBodyWritten = new AtomicLong(); private AsyncHandler.STATE currentState; - private String wsRequestURI; + private UriComponents wsRequestURI; private boolean isWSRequest; private HandShake handshake; private ProtocolHandler protocolHandler; @@ -97,7 +99,7 @@ private HttpTxContext(final GrizzlyAsyncHttpProvider provider, final GrizzlyResp this.handler = handler; redirectsAllowed = this.provider.getClientConfig().isFollowRedirect(); maxRedirectCount = this.provider.getClientConfig().getMaxRedirects(); - this.requestUrl = request.getUrl(); + this.requestUri = request.getURI(); } // ---------------------------------------------------------- Public Methods @@ -160,12 +162,12 @@ public void setRequest(Request request) { this.request = request; } - public String getRequestUrl() { - return requestUrl; + public UriComponents getRequestUri() { + return requestUri; } - public void setRequestUrl(String requestUrl) { - this.requestUrl = requestUrl; + public void setRequestUri(UriComponents requestUri) { + this.requestUri = requestUri; } public AsyncHandler getHandler() { @@ -232,11 +234,11 @@ public void setCurrentState(AsyncHandler.STATE currentState) { this.currentState = currentState; } - public String getWsRequestURI() { + public UriComponents getWsRequestURI() { return wsRequestURI; } - public void setWsRequestURI(String wsRequestURI) { + public void setWsRequestURI(UriComponents wsRequestURI) { this.wsRequestURI = wsRequestURI; } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 4b9d7fdf19..5d7a3009ba 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -218,7 +218,7 @@ private boolean sendAsGrizzlyRequest( return true; } - if (isUpgradeRequest(httpTxContext.getHandler()) && isWSRequest(httpTxContext.getRequestUrl())) { + if (isUpgradeRequest(httpTxContext.getHandler()) && isWSRequest(httpTxContext.getRequestUri())) { httpTxContext.setWSRequest(true); convertToUpgradeRequest(httpTxContext); } @@ -238,7 +238,7 @@ private boolean sendAsGrizzlyRequest( final int port = uri.getPort(); requestPacket.setRequestURI(uri.getHost() + ':' + (port == -1 ? 443 : port)); } else { - requestPacket.setRequestURI(uri.getPath()); + requestPacket.setRequestURI(uri.getNonEmptyPath()); } final BodyHandler bodyHandler = isPayloadAllowed(method) ? @@ -257,7 +257,7 @@ private boolean sendAsGrizzlyRequest( if (httpTxContext.isWSRequest()) { try { - final URI wsURI = new URI(httpTxContext.getWsRequestURI()); + final URI wsURI = httpTxContext.getWsRequestURI().toURI(); httpTxContext.setProtocolHandler(Version.RFC6455.createHandler(true)); httpTxContext.setHandshake(httpTxContext.getProtocolHandler().createHandShake(wsURI)); requestPacket = (HttpRequestPacket) httpTxContext.getHandshake().composeHeaders().getHttpHeader(); @@ -462,21 +462,18 @@ private static boolean isUpgradeRequest(final AsyncHandler handler) { return (handler instanceof UpgradeHandler); } - private static boolean isWSRequest(final String requestUri) { - return (requestUri.charAt(0) == 'w' && requestUri.charAt(1) == 's'); + private static boolean isWSRequest(final UriComponents requestUri) { + return requestUri.getScheme().startsWith("ws"); } private static void convertToUpgradeRequest(final HttpTxContext ctx) { - final int colonIdx = ctx.getRequestUrl().indexOf(':'); - - if (colonIdx < 2 || colonIdx > 3) { - throw new IllegalArgumentException("Invalid websocket URL: " + ctx.getRequestUrl()); - } - - final StringBuilder sb = new StringBuilder(ctx.getRequestUrl()); - sb.replace(0, colonIdx, ((colonIdx == 2) ? "http" : "https")); - ctx.setWsRequestURI(ctx.getRequestUrl()); - ctx.setRequestUrl(sb.toString()); + + UriComponents originalUri = ctx.getRequestUri(); + String newScheme = originalUri.getScheme().equalsIgnoreCase("https")? "wss" : "ws"; + ctx.setRequestUri(originalUri.withNewScheme(newScheme)); + + ctx.setWsRequestURI(ctx.getRequestUri()); + ctx.setRequestUri(originalUri.withNewScheme(newScheme)); } private void addGeneralHeaders(final Request request, final HttpRequestPacket requestPacket) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index 5178d7dd4c..f233d40e1f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -62,7 +62,7 @@ public NextAction handleWrite(FilterChainContext ctx) throws IOException { assert (context != null); Request req = context.getRequest(); if (!secure) { - request.setRequestURI(req.getURI().toString()); + request.setRequestURI(req.getURI().toUrl()); } addProxyHeaders(getRealm(req), request); return ctx.getInvokeAction(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java index 8bebb92d5d..191be251d8 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java @@ -67,7 +67,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT responsePacket.setSkipRemainder(true); // ignore the remainder of the response final Request req = httpTransactionContext.getRequest(); - realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getURI().getPath()) + realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getURI().getNonEmptyPath()) .setMethodName(req.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(auth).build(); String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH); if (lowerCaseAuth.startsWith("basic")) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java index a59d23876b..d7572e2ace 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/RedirectHandler.java @@ -75,7 +75,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT httpTransactionContext.setFuture(null); newContext.setInvocationStatus(CONTINUE); newContext.setRequest(requestToSend); - newContext.setRequestUrl(requestToSend.getUrl()); + newContext.setRequestUri(requestToSend.getURI()); HttpTxContext.set(ctx, newContext); httpTransactionContext.getProvider().execute(c, requestToSend, newContext.getHandler(), newContext.getFuture(), newContext); return false; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 3326fde184..b7caaa25cb 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -87,7 +87,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); return newRealmBuilder(realm)// - .setUri(uri.getPath())// + .setUri(uri.getNonEmptyPath())// .setMethodName(request.getMethod())// .setScheme(Realm.AuthScheme.KERBEROS)// .build(); @@ -127,7 +127,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p future.getAndSetAuth(false); return newRealmBuilder(realm)// .setScheme(realm.getAuthScheme())// - .setUri(uri.getPath())// + .setUri(uri.getNonEmptyPath())// .setMethodName(request.getMethod())// .setNtlmMessageType2Received(true)// .build(); @@ -137,7 +137,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; return newRealmBuilder(realm)// .setScheme(authScheme)// - .setUri(request.getURI().getPath())// + .setUri(request.getURI().getNonEmptyPath())// .setMethodName(request.getMethod())// .build(); } @@ -153,7 +153,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) - .setUri(request.getURI().getPath())// + .setUri(request.getURI().getNonEmptyPath())// .setMethodName(request.getMethod()).build(); } @@ -214,9 +214,9 @@ private final String computeRealmURI(Realm realm, UriComponents requestURI) { } } else { if (realm.isOmitQuery() || !isNonEmpty(requestURI.getQuery())) { - return requestURI.getPath(); + return requestURI.getNonEmptyPath(); } else { - return requestURI.getPath() + "?" + requestURI.getQuery(); + return requestURI.getNonEmptyPath() + "?" + requestURI.getQuery(); } } } @@ -241,7 +241,7 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req return true; } } else { - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(request.getURI().getPath()) + newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(request.getURI().getNonEmptyPath()) .setMethodName(request.getMethod()).setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index c62cbce5eb..eee4f6e6e3 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -79,10 +79,10 @@ else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithS return uri.toString(); else if (uri.getQuery() != null) - return uri.getPath() + "?" + uri.getQuery(); + return uri.getNonEmptyPath() + "?" + uri.getQuery(); else - return uri.getPath(); + return uri.getNonEmptyPath(); } private String hostHeader(Request request, UriComponents uri, Realm realm) { From 6fcbe4220b89773e8b95ee3d3895496dcb430ffa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 20:54:25 +0200 Subject: [PATCH 0127/2070] Move UriComponents.getNonEmptyPath to AsyncHttpProviderUtils --- .../asynchttpclient/uri/UriComponents.java | 9 ------ .../util/AsyncHttpProviderUtils.java | 11 +++++++ .../filters/AsyncHttpClientFilter.java | 3 +- .../statushandler/AuthorizationHandler.java | 3 +- .../providers/netty/handler/HttpProtocol.java | 29 ++++++++++++------- .../netty/request/NettyRequestFactory.java | 13 +++++---- 6 files changed, 41 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java index 5343071e61..cc9b6f08e8 100644 --- a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java +++ b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java @@ -66,15 +66,6 @@ public String getQuery() { return query; } - /** - * Convenient for HTTP layer when targeting server root - * - * @return the raw path or "/" if it's null - */ - public String getNonEmptyPath() { - return isNonEmpty(path) ? path : "/"; - } - public String getPath() { return path; } diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index dcd6164c9a..49ed3a4f45 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.util; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.HttpResponseBodyPart; @@ -102,6 +104,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() : "/"; + } + 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")) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 5d7a3009ba..dfca7a3805 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -16,6 +16,7 @@ import static org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter.getHandshakeError; import static org.asynchttpclient.providers.grizzly.GrizzlyAsyncHttpProvider.NTLM_ENGINE; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; @@ -238,7 +239,7 @@ private boolean sendAsGrizzlyRequest( final int port = uri.getPort(); requestPacket.setRequestURI(uri.getHost() + ':' + (port == -1 ? 443 : port)); } else { - requestPacket.setRequestURI(uri.getNonEmptyPath()); + requestPacket.setRequestURI(getNonEmptyPath(uri)); } final BodyHandler bodyHandler = isPayloadAllowed(method) ? diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java index 191be251d8..16416b73dc 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java @@ -13,6 +13,7 @@ package org.asynchttpclient.providers.grizzly.statushandler; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.STOP; import org.asynchttpclient.Realm; @@ -67,7 +68,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT responsePacket.setSkipRemainder(true); // ignore the remainder of the response final Request req = httpTransactionContext.getRequest(); - realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getURI().getNonEmptyPath()) + realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(getNonEmptyPath(req.getURI())) .setMethodName(req.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(auth).build(); String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH); if (lowerCaseAuth.startsWith("basic")) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index b7caaa25cb..0694b5a510 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -20,6 +20,7 @@ import static io.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncHandler; @@ -87,7 +88,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); return newRealmBuilder(realm)// - .setUri(uri.getNonEmptyPath())// + .setUri(getNonEmptyPath(uri))// .setMethodName(request.getMethod())// .setScheme(Realm.AuthScheme.KERBEROS)// .build(); @@ -127,7 +128,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p future.getAndSetAuth(false); return newRealmBuilder(realm)// .setScheme(realm.getAuthScheme())// - .setUri(uri.getNonEmptyPath())// + .setUri(getNonEmptyPath(uri))// .setMethodName(request.getMethod())// .setNtlmMessageType2Received(true)// .build(); @@ -137,7 +138,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; return newRealmBuilder(realm)// .setScheme(authScheme)// - .setUri(request.getURI().getNonEmptyPath())// + .setUri(getNonEmptyPath(request.getURI()))// .setMethodName(request.getMethod())// .build(); } @@ -153,7 +154,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) - .setUri(request.getURI().getNonEmptyPath())// + .setUri(getNonEmptyPath(request.getURI()))// .setMethodName(request.getMethod()).build(); } @@ -208,15 +209,16 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) { private final String computeRealmURI(Realm realm, UriComponents requestURI) { if (realm.isUseAbsoluteURI()) { if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { - return requestURI.withNewQuery(null).toString(); + return requestURI.withNewQuery(null).toUrl(); } else { - return requestURI.toString(); + return requestURI.toUrl(); } } else { + String path = getNonEmptyPath(requestURI); if (realm.isOmitQuery() || !isNonEmpty(requestURI.getQuery())) { - return requestURI.getNonEmptyPath(); + return path; } else { - return requestURI.getNonEmptyPath() + "?" + requestURI.getQuery(); + return path + "?" + requestURI.getQuery(); } } } @@ -241,9 +243,14 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req return true; } } else { - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(request.getURI().getNonEmptyPath()) - .setMethodName(request.getMethod()).setUsePreemptiveAuth(true) - .parseWWWAuthenticateHeader(authenticateHeaders.get(0)).build(); + newRealm = new Realm.RealmBuilder()// + .clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(getNonEmptyPath(request.getURI()))// + .setMethodName(request.getMethod())// + .setUsePreemptiveAuth(true)// + .parseWWWAuthenticateHeader(authenticateHeaders.get(0))// + .build(); } String realmURI = computeRealmURI(newRealm, request.getURI()); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index eee4f6e6e3..d777c9d1c6 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -19,6 +19,7 @@ import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpRequest; @@ -78,11 +79,13 @@ private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) return uri.toString(); - else if (uri.getQuery() != null) - return uri.getNonEmptyPath() + "?" + uri.getQuery(); - - else - return uri.getNonEmptyPath(); + else { + String path = getNonEmptyPath(uri); + if (isNonEmpty(uri.getQuery())) + return path + "?" + uri.getQuery(); + else + return path; + } } private String hostHeader(Request request, UriComponents uri, Realm realm) { From d756d2606f2033690b69d5c024b042c90c520cf3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:11:11 +0200 Subject: [PATCH 0128/2070] Minor fix --- .../providers/grizzly/filters/AsyncHttpClientFilter.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index dfca7a3805..f1be2da91d 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -470,10 +470,8 @@ private static boolean isWSRequest(final UriComponents requestUri) { private static void convertToUpgradeRequest(final HttpTxContext ctx) { UriComponents originalUri = ctx.getRequestUri(); - String newScheme = originalUri.getScheme().equalsIgnoreCase("https")? "wss" : "ws"; - ctx.setRequestUri(originalUri.withNewScheme(newScheme)); - - ctx.setWsRequestURI(ctx.getRequestUri()); + String newScheme = originalUri.getScheme().equalsIgnoreCase("https") ? "wss" : "ws"; + ctx.setWsRequestURI(originalUri); ctx.setRequestUri(originalUri.withNewScheme(newScheme)); } From b65a7a3adfdb0a59db779b0ec6b3dbbf3a7bf7ad Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:32:33 +0200 Subject: [PATCH 0129/2070] Make all providers honor Realm.isOmitQuery and isUseAbsoluteURI, close #607 --- .../main/java/org/asynchttpclient/Realm.java | 13 +++---- .../asynchttpclient/uri/UriComponents.java | 9 +++++ .../util/AuthenticatorUtils.java | 14 +++++++- .../java/org/asynchttpclient/RealmTest.java | 5 +-- .../statushandler/AuthorizationHandler.java | 3 +- .../ProxyAuthorizationHandler.java | 2 +- .../providers/netty/handler/HttpProtocol.java | 34 +++++-------------- 7 files changed, 42 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index 45594ad4ec..bc71d0d3d3 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -18,6 +18,7 @@ import static org.asynchttpclient.util.MiscUtils.isNonEmpty; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.StandardCharsets; import java.nio.charset.Charset; @@ -42,7 +43,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; @@ -58,7 +59,7 @@ public enum AuthScheme { } private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, - String qop, String nc, String cnonce, String uri, String method, boolean usePreemptiveAuth, String ntlmDomain, String enc, + String qop, String nc, String cnonce, UriComponents uri, String method, boolean usePreemptiveAuth, String ntlmDomain, String enc, String host, boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery) { this.principal = principal; @@ -133,7 +134,7 @@ public String getCnonce() { return cnonce; } - public String getUri() { + public UriComponents getUri() { return uri; } @@ -268,7 +269,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 domain = System.getProperty("http.auth.ntlm.domain", ""); @@ -386,11 +387,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/api/src/main/java/org/asynchttpclient/uri/UriComponents.java b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java index cc9b6f08e8..3fe3c224c6 100644 --- a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java +++ b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java @@ -121,6 +121,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,// diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index 349b50cf14..c147355612 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -16,6 +16,7 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; +import org.asynchttpclient.uri.UriComponents; import java.security.NoSuchAlgorithmException; @@ -31,13 +32,24 @@ public static String computeBasicAuthentication(ProxyServer proxyServer) { return "Basic " + Base64.encode(s.getBytes(proxyServer.getCharset())); } + 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 { 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()); diff --git a/api/src/test/java/org/asynchttpclient/RealmTest.java b/api/src/test/java/org/asynchttpclient/RealmTest.java index 11873f0126..23315a92e6 100644 --- a/api/src/test/java/org/asynchttpclient/RealmTest.java +++ b/api/src/test/java/org/asynchttpclient/RealmTest.java @@ -16,6 +16,7 @@ import org.asynchttpclient.Realm.AuthScheme; import org.asynchttpclient.Realm.RealmBuilder; +import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.StandardCharsets; import org.testng.annotations.Test; @@ -60,7 +61,7 @@ private void testOldDigest(String qop) { String realm = "realm"; String nonce = "nonce"; String method = "GET"; - String uri = "/foo"; + UriComponents uri = UriComponents.create("http://ahc.io/foo"); RealmBuilder builder = new RealmBuilder(); builder.setPrincipal(user).setPassword(pass); builder.setNonce(nonce); @@ -85,7 +86,7 @@ public void testStrongDigest() { String realm = "realm"; String nonce = "nonce"; String method = "GET"; - String uri = "/foo"; + UriComponents uri = UriComponents.create("http://ahc.io/foo"); String qop = "auth"; RealmBuilder builder = new RealmBuilder(); builder.setPrincipal(user).setPassword(pass); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java index 16416b73dc..fb12218ba3 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java @@ -13,7 +13,6 @@ package org.asynchttpclient.providers.grizzly.statushandler; -import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.providers.grizzly.statushandler.StatusHandler.InvocationStatus.STOP; import org.asynchttpclient.Realm; @@ -68,7 +67,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT responsePacket.setSkipRemainder(true); // ignore the remainder of the response final Request req = httpTransactionContext.getRequest(); - realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(getNonEmptyPath(req.getURI())) + realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getURI()) .setMethodName(req.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(auth).build(); String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH); if (lowerCaseAuth.startsWith("basic")) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java index 1e090e69ea..0189796e64 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java @@ -60,7 +60,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT .select(req.getURI()); String principal = proxyServer.getPrincipal(); String password = proxyServer.getPassword(); - Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri("/") + Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri(req.getURI().withNewPath("/").withNewQuery(null)) .setMethodName(Method.CONNECT.getMethodString()).setUsePreemptiveAuth(true).parseProxyAuthenticateHeader(proxyAuth).build(); String proxyAuthLowerCase = proxyAuth.toLowerCase(Locale.ENGLISH); if (proxyAuthLowerCase.startsWith("basic")) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 0694b5a510..0a58c32937 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -88,7 +88,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); return newRealmBuilder(realm)// - .setUri(getNonEmptyPath(uri))// + .setUri(uri)// .setMethodName(request.getMethod())// .setScheme(Realm.AuthScheme.KERBEROS)// .build(); @@ -119,16 +119,16 @@ 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(); if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); - UriComponents uri = request.getURI(); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); future.getAndSetAuth(false); return newRealmBuilder(realm)// .setScheme(realm.getAuthScheme())// - .setUri(getNonEmptyPath(uri))// + .setUri(uri)// .setMethodName(request.getMethod())// .setNtlmMessageType2Received(true)// .build(); @@ -138,7 +138,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; return newRealmBuilder(realm)// .setScheme(authScheme)// - .setUri(getNonEmptyPath(request.getURI()))// + .setUri(uri)// .setMethodName(request.getMethod())// .build(); } @@ -154,7 +154,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) - .setUri(getNonEmptyPath(request.getURI()))// + .setUri(request.getURI())// .setMethodName(request.getMethod()).build(); } @@ -206,23 +206,6 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) { } } - private final String computeRealmURI(Realm realm, UriComponents requestURI) { - if (realm.isUseAbsoluteURI()) { - if (realm.isOmitQuery() && isNonEmpty(requestURI.getQuery())) { - return requestURI.withNewQuery(null).toUrl(); - } else { - return requestURI.toUrl(); - } - } else { - String path = getNonEmptyPath(requestURI); - if (realm.isOmitQuery() || !isNonEmpty(requestURI.getQuery())) { - return path; - } else { - return path + "?" + requestURI.getQuery(); - } - } - } - private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws Exception { if (statusCode == UNAUTHORIZED.code() && realm != null) { @@ -246,15 +229,14 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req newRealm = new Realm.RealmBuilder()// .clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(getNonEmptyPath(request.getURI()))// + .setUri(request.getURI())// .setMethodName(request.getMethod())// .setUsePreemptiveAuth(true)// .parseWWWAuthenticateHeader(authenticateHeaders.get(0))// .build(); } - String realmURI = computeRealmURI(newRealm, request.getURI()); - Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); + Realm nr = newRealm; final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); LOGGER.debug("Sending authentication to {}", request.getURI()); @@ -318,7 +300,7 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri("/")// + .setUri(request.getURI().withNewPath("/").withNewQuery(null))// .setMethodName(HttpMethod.CONNECT.name())// .setUsePreemptiveAuth(true)// .parseProxyAuthenticateHeader(proxyAuthenticateHeaders.get(0))// From c809a504e8ce7007c427aaa0f54bef7e3bf1e701 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:35:13 +0200 Subject: [PATCH 0130/2070] minor clean up --- .../main/java/org/asynchttpclient/RequestBuilderBase.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java index 8629599db9..1b1a94bad2 100644 --- a/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java +++ b/api/src/main/java/org/asynchttpclient/RequestBuilderBase.java @@ -594,13 +594,7 @@ private void computeFinalUri() { String newQuery = queryComputer.computeFullQueryString(request.uri.getQuery(), queryParams); - request.uri = new UriComponents(// - request.uri.getScheme(),// - request.uri.getUserInfo(),// - request.uri.getHost(),// - request.uri.getPort(),// - request.uri.getPath(),// - newQuery); + request.uri = request.uri.withNewQuery(newQuery); } public Request build() { From 4a87ef77a41ee2bdb000175ab57732b35a9d3e8d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:37:20 +0200 Subject: [PATCH 0131/2070] Minor clean up --- .../grizzly/statushandler/ProxyAuthorizationHandler.java | 2 +- .../asynchttpclient/providers/netty/handler/HttpProtocol.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java index 0189796e64..172806b2fa 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java @@ -60,7 +60,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT .select(req.getURI()); String principal = proxyServer.getPrincipal(); String password = proxyServer.getPassword(); - Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri(req.getURI().withNewPath("/").withNewQuery(null)) + Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri(req.getURI().withNewPath("/")).setOmitQuery(true) .setMethodName(Method.CONNECT.getMethodString()).setUsePreemptiveAuth(true).parseProxyAuthenticateHeader(proxyAuth).build(); String proxyAuthLowerCase = proxyAuth.toLowerCase(Locale.ENGLISH); if (proxyAuthLowerCase.startsWith("basic")) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 0a58c32937..91f237118f 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -300,7 +300,8 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(request.getURI().withNewPath("/").withNewQuery(null))// + .setUri(request.getURI().withNewPath("/"))// + .setOmitQuery(true)// .setMethodName(HttpMethod.CONNECT.name())// .setUsePreemptiveAuth(true)// .parseProxyAuthenticateHeader(proxyAuthenticateHeaders.get(0))// From 683e24c86d7f8b03886a2a5a080938f9a2a39ade Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 05:53:34 +0200 Subject: [PATCH 0132/2070] Better proxy auth --- .../main/java/org/asynchttpclient/Realm.java | 46 +++++++++++++------ .../asynchttpclient/uri/UriComponents.java | 11 ----- .../util/AuthenticatorUtils.java | 16 ++++--- .../ProxyAuthorizationHandler.java | 2 +- .../providers/netty/handler/HttpProtocol.java | 3 +- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Realm.java b/api/src/main/java/org/asynchttpclient/Realm.java index bc71d0d3d3..1f5434f62a 100644 --- a/api/src/main/java/org/asynchttpclient/Realm.java +++ b/api/src/main/java/org/asynchttpclient/Realm.java @@ -53,6 +53,7 @@ public class Realm { private final Charset charset; private final boolean useAbsoluteURI; private final boolean omitQuery; + private final boolean targetProxy; public enum AuthScheme { DIGEST, BASIC, NTLM, SPNEGO, KERBEROS, NONE @@ -60,7 +61,7 @@ public enum AuthScheme { private Realm(AuthScheme scheme, String principal, String password, String realmName, String nonce, String algorithm, String response, String qop, String nc, String cnonce, UriComponents uri, String method, boolean usePreemptiveAuth, String ntlmDomain, String enc, - String host, boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery) { + String host, boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery, boolean targetProxy) { this.principal = principal; this.password = password; @@ -83,6 +84,7 @@ private Realm(AuthScheme scheme, String principal, String password, String realm this.charset = enc != null ? Charset.forName(enc) : null; this.useAbsoluteURI = useAbsoluteURI; this.omitQuery = omitQuery; + this.targetProxy = targetProxy; } public String getPrincipal() { @@ -188,7 +190,11 @@ public boolean isUseAbsoluteURI() { public boolean isOmitQuery() { return omitQuery; } - + + public boolean isTargetProxy() { + return targetProxy; + } + @Override public boolean equals(Object o) { if (this == o) @@ -271,20 +277,21 @@ public static class RealmBuilder { private String cnonce = ""; private UriComponents uri; private String methodName = "GET"; - private boolean usePreemptive = false; - private String domain = System.getProperty("http.auth.ntlm.domain", ""); + private boolean usePreemptive; + private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); private String enc = StandardCharsets.UTF_8.name(); private String host = "localhost"; - private boolean messageType2Received = false; + private boolean messageType2Received; private boolean useAbsoluteURI = true; - private boolean omitQuery = false; + private boolean omitQuery; + private boolean targetProxy; 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; } @@ -436,7 +443,16 @@ 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")); setNonce(match(headerLine, "nonce")); @@ -464,6 +480,7 @@ public RealmBuilder parseProxyAuthenticateHeader(String headerLine) { } else { setScheme(AuthScheme.BASIC); } + setTargetProxy(true); return this; } @@ -484,6 +501,9 @@ public RealmBuilder clone(Realm clone) { setNtlmDomain(clone.getNtlmDomain()); setNtlmHost(clone.getNtlmHost()); setNtlmMessageType2Received(clone.isNtlmMessageType2Received()); + setUseAbsoluteURI(clone.isUseAbsoluteURI()); + setOmitQuery(clone.isOmitQuery()); + setTargetProxy(clone.isTargetProxy()); return this; } @@ -511,8 +531,8 @@ private String match(String headerLine, String token) { // = to skip match += token.length() + 1; - int traillingComa = headerLine.indexOf(",", match); - String value = headerLine.substring(match, traillingComa > 0 ? traillingComa : headerLine.length()); + int trailingComa = headerLine.indexOf(",", match); + String value = headerLine.substring(match, trailingComa > 0 ? trailingComa : headerLine.length()); value = value.length() > 0 && value.charAt(value.length() - 1) == '"' ? value.substring(0, value.length() - 1) : value; return value.charAt(0) == '"' ? value.substring(1) : value; } @@ -609,7 +629,7 @@ public Realm build() { } return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName, - usePreemptive, domain, enc, host, messageType2Received, opaque, useAbsoluteURI, omitQuery); + usePreemptive, ntlmDomain, enc, host, messageType2Received, opaque, useAbsoluteURI, omitQuery, targetProxy); } } } diff --git a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java index 3fe3c224c6..898557d6a5 100644 --- a/api/src/main/java/org/asynchttpclient/uri/UriComponents.java +++ b/api/src/main/java/org/asynchttpclient/uri/UriComponents.java @@ -12,8 +12,6 @@ */ package org.asynchttpclient.uri; -import static org.asynchttpclient.util.MiscUtils.isNonEmpty; - import java.net.URI; import java.net.URISyntaxException; @@ -121,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/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index c147355612..a74d71a659 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -33,13 +33,17 @@ public static String computeBasicAuthentication(ProxyServer proxyServer) { } 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 = uri.getPath(); - return omitQuery ? path : path + "?" + uri.getQuery(); + 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(); + } } } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java index 172806b2fa..40564b2d2e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/ProxyAuthorizationHandler.java @@ -60,7 +60,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT .select(req.getURI()); String principal = proxyServer.getPrincipal(); String password = proxyServer.getPassword(); - Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri(req.getURI().withNewPath("/")).setOmitQuery(true) + Realm realm = new Realm.RealmBuilder().setPrincipal(principal).setPassword(password).setUri(req.getURI()).setOmitQuery(true) .setMethodName(Method.CONNECT.getMethodString()).setUsePreemptiveAuth(true).parseProxyAuthenticateHeader(proxyAuth).build(); String proxyAuthLowerCase = proxyAuth.toLowerCase(Locale.ENGLISH); if (proxyAuthLowerCase.startsWith("basic")) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 91f237118f..9bd2b36ee9 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -20,7 +20,6 @@ import static io.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; -import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.AsyncHandler; @@ -300,7 +299,7 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(request.getURI().withNewPath("/"))// + .setUri(request.getURI())// .setOmitQuery(true)// .setMethodName(HttpMethod.CONNECT.name())// .setUsePreemptiveAuth(true)// From 8b6fcee02d2134f465231496cd9eeccc5ad68245 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 13:54:31 +0200 Subject: [PATCH 0133/2070] Add #355 test on master: both Netty and Grizzly are OK --- .../asynchttpclient/async/BasicHttpsTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java index 24675057e7..513786fc91 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java @@ -25,9 +25,12 @@ import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig.Builder; import org.asynchttpclient.Response; +import org.testng.Assert; import org.testng.annotations.Test; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSession; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -125,4 +128,33 @@ public void reconnectsAfterFailedCertificationPath() throws Exception { c.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); + + 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(); + } + } } From 60830ebc76fc83097966702dd974c333859340ec Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 15:37:51 +0200 Subject: [PATCH 0134/2070] Missing acceptAnyCertificate propagation --- api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 8c8a4ba980..422f560af9 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -1133,6 +1133,7 @@ public Builder(AsyncHttpClientConfig prototype) { strict302Handling = prototype.isStrict302Handling(); useRelativeURIsWithSSLProxies = prototype.isUseRelativeURIsWithSSLProxies(); timeConverter = prototype.getTimeConverter(); + acceptAnyCertificate = prototype.isAcceptAnyCertificate(); } /** From e12a45b188283d166fa397f18e3cf7300bf8fe51 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Jul 2014 09:34:20 +0200 Subject: [PATCH 0135/2070] Fix extras/registry test --- extras/pom.xml | 7 ++++ .../AbstractAsyncHttpClientFactoryTest.java | 31 ++++++++++-------- .../extras/registry}/TestAsyncHttpClient.java | 12 ++++++- extras/registry/src/test/resources/300k.png | Bin 0 -> 265495 bytes .../src/test/resources/SimpleTextFile.txt | 1 + 5 files changed, 36 insertions(+), 15 deletions(-) rename {api/src/test/java/org/asynchttpclient => extras/registry/src/test/java/org/asynchttpclient/extras/registry}/TestAsyncHttpClient.java (87%) create mode 100644 extras/registry/src/test/resources/300k.png create mode 100644 extras/registry/src/test/resources/SimpleTextFile.txt diff --git a/extras/pom.xml b/extras/pom.xml index c220594e75..ab0b2dc70d 100644 --- a/extras/pom.xml +++ b/extras/pom.xml @@ -55,5 +55,12 @@ async-http-client-api ${project.version} + + org.asynchttpclient + async-http-client-api + ${project.version} + test + tests + \ No newline at end of file diff --git a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java index 4561a751ee..b4c05cc8be 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AbstractAsyncHttpClientFactoryTest.java @@ -17,7 +17,6 @@ import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.DefaultAsyncHttpClient; import org.asynchttpclient.Response; -import org.asynchttpclient.TestAsyncHttpClient; import org.asynchttpclient.async.util.EchoHandler; import org.asynchttpclient.async.util.TestUtils; import org.asynchttpclient.extras.registry.AsyncHttpClientFactory; @@ -36,6 +35,10 @@ public abstract class AbstractAsyncHttpClientFactoryTest { + public static final String TEST_CLIENT_CLASS_NAME = "org.asynchttpclient.extras.registry.TestAsyncHttpClient"; + public static final String BAD_CLIENT_CLASS_NAME = "org.asynchttpclient.extras.registry.BadAsyncHttpClient"; + public static final String NON_EXISTENT_CLIENT_CLASS_NAME = "org.asynchttpclient.extras.registry.NonExistentAsyncHttpClient"; + private Server server; private int port; @@ -114,27 +117,27 @@ public void testGetAsyncHttpClientStringConfig() { // =================================================================================================================================== @Test(groups = "fast") public void testFactoryWithSystemProperty() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, TEST_CLIENT_CLASS_NAME); Assert.assertTrue(AsyncHttpClientFactory.getAsyncHttpClient().getClass().equals(TestAsyncHttpClient.class)); } @Test(groups = "fast") public void testGetAsyncHttpClientConfigWithSystemProperty() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, TEST_CLIENT_CLASS_NAME); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); } @Test(groups = "fast") public void testGetAsyncHttpClientProviderWithSystemProperty() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, TEST_CLIENT_CLASS_NAME); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); } @Test(groups = "fast") public void testGetAsyncHttpClientConfigAndProviderWithSystemProperty() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, TEST_CLIENT_CLASS_NAME); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); @@ -142,7 +145,7 @@ public void testGetAsyncHttpClientConfigAndProviderWithSystemProperty() { @Test(groups = "fast") public void testGetAsyncHttpClientStringConfigWithSystemProperty() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, TEST_CLIENT_CLASS_NAME); AsyncHttpClient asyncHttpClient = AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), new AsyncHttpClientConfig.Builder().build()); Assert.assertTrue(asyncHttpClient.getClass().equals(TestAsyncHttpClient.class)); @@ -157,14 +160,14 @@ public void testGetAsyncHttpClientStringConfigWithSystemProperty() { // =================================================================================================================================== @Test(groups = "fast", expectedExceptions = BadAsyncHttpClientException.class) public void testFactoryWithBadAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, BAD_CLIENT_CLASS_NAME); AsyncHttpClientFactory.getAsyncHttpClient(); Assert.fail("BadAsyncHttpClientException should have been thrown before this point"); } @Test(groups = "fast") public void testGetAsyncHttpClientConfigWithBadAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, BAD_CLIENT_CLASS_NAME); try { AsyncHttpClientFactory.getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); } catch (AsyncHttpClientImplException e) { @@ -175,7 +178,7 @@ public void testGetAsyncHttpClientConfigWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientProviderWithBadAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, BAD_CLIENT_CLASS_NAME); try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null)); } catch (AsyncHttpClientImplException e) { @@ -186,7 +189,7 @@ public void testGetAsyncHttpClientProviderWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientConfigAndProviderWithBadAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, BAD_CLIENT_CLASS_NAME); try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null), new AsyncHttpClientConfig.Builder().build()); } catch (AsyncHttpClientImplException e) { @@ -197,7 +200,7 @@ public void testGetAsyncHttpClientConfigAndProviderWithBadAsyncHttpClient() { @Test(groups = "fast") public void testGetAsyncHttpClientStringConfigWithBadAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, BAD_CLIENT_CLASS_NAME); try { AsyncHttpClientFactory.getAsyncHttpClient(getAsyncHttpProvider(null).getClass().getName(), new AsyncHttpClientConfig.Builder().build()); @@ -215,7 +218,7 @@ public void testGetAsyncHttpClientStringConfigWithBadAsyncHttpClient() { */ @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testFactoryWithNonExistentAsyncHttpClient() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, NON_EXISTENT_CLIENT_CLASS_NAME); AsyncHttpClientFactory.getAsyncHttpClient(); Assert.fail("AsyncHttpClientImplException should have been thrown before this point"); } @@ -227,7 +230,7 @@ public void testFactoryWithNonExistentAsyncHttpClient() { @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testRepeatedCallsToBadAsyncHttpClient() { boolean exceptionCaught = false; - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, NON_EXISTENT_CLIENT_CLASS_NAME); try { AsyncHttpClientFactory.getAsyncHttpClient(); } catch (AsyncHttpClientImplException e) { @@ -260,7 +263,7 @@ private void assertClientWorks(AsyncHttpClient asyncHttpClient) { private void assertException(AsyncHttpClientImplException e) { InvocationTargetException t = (InvocationTargetException) e.getCause(); - Assert.assertTrue(t.getCause().getClass().equals(BadAsyncHttpClientException.class)); + Assert.assertTrue(t.getCause() instanceof BadAsyncHttpClientException); } } diff --git a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClient.java similarity index 87% rename from api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java rename to extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClient.java index 1d9ab99702..9d927287fc 100644 --- a/api/src/test/java/org/asynchttpclient/TestAsyncHttpClient.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/TestAsyncHttpClient.java @@ -10,7 +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 org.asynchttpclient; +package org.asynchttpclient.extras.registry; + +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.AsyncHttpProvider; +import org.asynchttpclient.BoundRequestBuilder; +import org.asynchttpclient.ListenableFuture; +import org.asynchttpclient.Request; +import org.asynchttpclient.Response; +import org.asynchttpclient.SignatureCalculator; import java.io.IOException; diff --git a/extras/registry/src/test/resources/300k.png b/extras/registry/src/test/resources/300k.png new file mode 100644 index 0000000000000000000000000000000000000000..bff4a8598918ed4945bc27db894230d8b5b7cc80 GIT binary patch literal 265495 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

PaQ)q~!Z}nw5+`R(>f%iv2-Q(|v{Kn?y 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

E;dnj|F+k_IVjB&&;(F4ZJK@Lu=C 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 J Date: Mon, 14 Jul 2014 14:19:54 +0200 Subject: [PATCH 0136/2070] Port refactored Netty Channel pool on master --- .../netty/channel/DefaultChannelPool.java | 320 ++++++++++-------- 1 file changed, 183 insertions(+), 137 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java index 54308e010a..a1c1c9f4ed 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java @@ -27,144 +27,207 @@ import io.netty.util.internal.chmv8.ConcurrentHashMapV8; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; /** * A simple implementation of {@link ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ public class DefaultChannelPool implements ChannelPool { - private final static Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); + private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); - private final ConcurrentHashMapV8 channel2IdleChannel = new ConcurrentHashMapV8(); - private final ConcurrentHashMapV8 channel2CreationDate = new ConcurrentHashMapV8(); - private final AtomicBoolean closed = new AtomicBoolean(false); + private final ConcurrentHashMapV8 channel2Creation = new ConcurrentHashMapV8(); + 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 int maxConnectionLifeTimeInMs; + 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(AsyncHttpClientConfig config, Timer nettyTimer) { + public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { this(config.getMaxTotalConnections(),// config.getMaxConnectionPerHost(),// config.getIdleConnectionInPoolTimeoutInMs(),// - config.isSslConnectionPoolEnabled(),// config.getMaxConnectionLifeTimeInMs(),// - nettyTimer); + config.isSslConnectionPoolEnabled(),// + hashedWheelTimer); } public DefaultChannelPool(// int maxTotalConnections,// int maxConnectionPerHost,// long maxIdleTime,// + int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// - int maxConnectionLifeTimeInMs,// Timer nettyTimer) { this.maxTotalConnections = maxTotalConnections; + maxTotalConnectionsDisabled = maxTotalConnections <= 0; this.maxConnectionPerHost = maxConnectionPerHost; + maxConnectionPerHostDisabled = maxConnectionPerHost <= 0; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionTTL = maxConnectionTTL; + maxConnectionTTLDisabled = maxConnectionTTL <= 0; this.nettyTimer = nettyTimer; - if (maxIdleTime > 0L) { + 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, maxIdleTime, TimeUnit.MILLISECONDS); + nettyTimer.newTimeout(task, cleanerPeriod, TimeUnit.MILLISECONDS); } - private static final class IdleChannel { + 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(String key, Channel channel) { - if (key == null) - throw new NullPointerException("key"); + IdleChannel(Channel channel, long start) { if (channel == null) throw new NullPointerException("channel"); - this.key = key; this.channel = channel; - this.start = millisTime(); + 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 != null ? channel.hashCode() : 0; + return channel.hashCode(); } } - private class IdleChannelDetector implements TimerTask { + private boolean isTTLExpired(Channel channel, long now) { + if (maxConnectionTTLDisabled) + return false; - @Override - public void run(Timeout timeout) throws Exception { - try { - if (closed.get()) - return; + ChannelCreation creation = channel2Creation.get(channel); + return creation == null || now - creation.creationTime >= maxConnectionTTL; + } - if (LOGGER.isDebugEnabled()) { - Set keys = connectionsPool.keySet(); + private boolean isRemotelyClosed(Channel channel) { + return !channel.isOpen(); + } - for (String s : keys) { - LOGGER.debug("Entry count for : {} : {}", s, connectionsPool.get(s).size()); - } - } + private final class IdleChannelDetector implements TimerTask { - List channelsInTimeout = new ArrayList(); - long currentTime = millisTime(); + private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) { + return !maxIdleTimeDisabled && now - idleChannel.start >= maxIdleTime; + } - for (IdleChannel idleChannel : channel2IdleChannel.values()) { - long age = currentTime - idleChannel.start; - if (age > 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); + } + } - LOGGER.debug("Adding Candidate Idle Channel {}", idleChannel.channel); + return idleTimeoutChannels != null ? idleTimeoutChannels : Collections. emptyList(); + } - // store in an unsynchronized list to minimize the impact on the ConcurrentHashMap. - channelsInTimeout.add(idleChannel); - } - } - long endConcurrentLoop = millisTime(); - - for (IdleChannel idleChannel : channelsInTimeout) { - Object attachment = Channels.getDefaultAttribute(idleChannel.channel); - if (attachment != null) { - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - - if (!future.isDone() && !future.isCancelled()) { - LOGGER.debug("Future not in appropriate state %s\n", future); - continue; - } - } - } + private boolean isChannelCloseable(Channel channel) { + boolean closeable = true; + Object attachment = Channels.getDefaultAttribute(channel); + 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; + } - if (remove(idleChannel)) { + 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 (LOGGER.isTraceEnabled()) { - int openChannels = 0; - for (ConcurrentLinkedQueue hostChannels : connectionsPool.values()) { - openChannels += hostChannels.size(); + if (isClosed.get()) + return; + + try { + if (LOGGER.isDebugEnabled()) { + for (String key : connectionsPool.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, connectionsPool.get(key).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)); } + + 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); } @@ -173,137 +236,120 @@ 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} */ - public boolean offer(String uri, Channel channel) { - if (closed.get() || (!sslConnectionPoolEnabled && uri.startsWith("https"))) + public boolean offer(String key, Channel channel) { + if (isClosed.get() || (!sslConnectionPoolEnabled && key.startsWith("https"))) return false; - Long createTime = channel2CreationDate.get(channel); - if (createTime == null) { - channel2CreationDate.putIfAbsent(channel, millisTime()); + long now = millisTime(); - } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { - LOGGER.debug("Channel {} expired", channel); + if (isTTLExpired(channel, now)) return false; - } - - LOGGER.debug("Adding uri: {} for channel {}", uri, channel); - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); - if (pooledConnectionForKey == null) { + ConcurrentLinkedQueue idleConnectionForKey = connectionsPool.get(key); + if (idleConnectionForKey == null) { ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - pooledConnectionForKey = connectionsPool.putIfAbsent(uri, newPool); - if (pooledConnectionForKey == null) - pooledConnectionForKey = newPool; + idleConnectionForKey = connectionsPool.putIfAbsent(key, newPool); + if (idleConnectionForKey == null) + idleConnectionForKey = newPool; } - boolean added; - int size = pooledConnectionForKey.size(); - if (maxConnectionPerHost == -1 || size < maxConnectionPerHost) { - IdleChannel idleChannel = new IdleChannel(uri, channel); - synchronized (pooledConnectionForKey) { - added = pooledConnectionForKey.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; + 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 uri) { - if (!sslConnectionPoolEnabled && uri.startsWith("https")) { + public Channel poll(String key) { + if (!sslConnectionPoolEnabled && key.startsWith("https")) return null; - } IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(key); if (pooledConnectionForKey != null) { - boolean poolEmpty = false; - while (!poolEmpty && idleChannel == null) { - if (pooledConnectionForKey.size() > 0) { - synchronized (pooledConnectionForKey) { - idleChannel = pooledConnectionForKey.poll(); - if (idleChannel != null) { - channel2IdleChannel.remove(idleChannel.channel); - } - } - } + while (idleChannel == null) { + idleChannel = pooledConnectionForKey.poll(); - if (idleChannel == null) { - poolEmpty = true; - } else if (!idleChannel.channel.isActive() || !idleChannel.channel.isOpen()) { + if (idleChannel == null) + // pool is empty + break; + else if (isRemotelyClosed(idleChannel.channel)) { idleChannel = null; - LOGGER.trace("Channel not connected or not opened!"); + LOGGER.trace("Channel not connected or not opened, probably remotely closed!"); } } } - return idleChannel != null ? idleChannel.channel : null; - } - - private boolean remove(IdleChannel pooledChannel) { - if (pooledChannel == null || closed.get()) - return false; - - boolean isRemoved = false; - ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.key); - if (pooledConnectionForHost != null) { - isRemoved = pooledConnectionForHost.remove(pooledChannel); - } - return isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; + if (idleChannel != null) { + size.decrementAndGet(); + return idleChannel.channel; + } else + return null; } /** * {@inheritDoc} */ public boolean removeAll(Channel channel) { - channel2CreationDate.remove(channel); - return !closed.get() && remove(channel2IdleChannel.get(channel)); + ChannelCreation creation = channel2Creation.remove(channel); + return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); } /** * {@inheritDoc} */ public boolean canCacheConnection() { - return !closed.get() && (maxTotalConnections == -1 || channel2IdleChannel.size() < maxTotalConnections); + // 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 (closed.getAndSet(true)) + if (isClosed.getAndSet(true)) return; - for (Channel channel : channel2IdleChannel.keySet()) { - close(channel); + for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (IdleChannel idleChannel : pool) + close(idleChannel.channel); } + connectionsPool.clear(); - channel2IdleChannel.clear(); - channel2CreationDate.clear(); + channel2Creation.clear(); + size.set(0); } private void close(Channel channel) { try { Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - channel2CreationDate.remove(channel); + channel2Creation.remove(channel); channel.close(); } catch (Throwable t) { // noop } } - public final String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", channel2IdleChannel.size()); + public String toString() { + return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); } } From cc92c540c5f704b686f0c6cecf5800686e868259 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 14:34:53 +0200 Subject: [PATCH 0137/2070] Refactor Netty provider config --- .../netty/NettyAsyncHttpProviderConfig.java | 213 ++++++++---------- .../providers/netty/channel/Channels.java | 35 +-- .../netty/NettyAsyncProviderBasicTest.java | 6 +- 3 files changed, 104 insertions(+), 150 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index ac75499993..b03b6ef31b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -22,8 +22,6 @@ import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; @@ -38,67 +36,9 @@ /** * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ -public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { +public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig, Object> { - private final static Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProviderConfig.class); - - /** - * Allow configuring the Netty's event loop. - */ - private EventLoopGroup eventLoopGroup; - - private AdditionalChannelInitializer httpAdditionalChannelInitializer; - private AdditionalChannelInitializer wsAdditionalChannelInitializer; - private AdditionalChannelInitializer httpsAdditionalChannelInitializer; - private AdditionalChannelInitializer wssAdditionalChannelInitializer; - - /** - * HttpClientCodec's maxInitialLineLength - */ - private int maxInitialLineLength = 4096; - - /** - * HttpClientCodec's maxHeaderSize - */ - private int maxHeaderSize = 8192; - - /** - * HttpClientCodec's maxChunkSize - */ - private int maxChunkSize = 8192; - - /** - * Use direct {@link java.nio.ByteBuffer} - */ - public final static String USE_DIRECT_BYTEBUFFER = "bufferFactory"; - - /** - * Allow nested request from any {@link org.asynchttpclient.AsyncHandler} - */ - public final static String DISABLE_NESTED_REQUEST = "disableNestedRequest"; - - /** - * See {@link java.net.Socket#setReuseAddress(boolean)} - */ - public final static String REUSE_ADDRESS = ChannelOption.SO_REUSEADDR.name(); - - private final Map properties = new HashMap(); - - private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); - - private ChannelPool channelPool; - - private boolean disableZeroCopy; - - private Timer nettyTimer; - - private long handshakeTimeoutInMillis; - - private SSLEngineFactory sslEngineFactory; - - public NettyAsyncHttpProviderConfig() { - properties.put(REUSE_ADDRESS, Boolean.FALSE); - } + private final Map, Object> properties = new HashMap, Object>(); /** * Add a property that will be used when the AsyncHttpClient initialize its @@ -108,16 +48,14 @@ public NettyAsyncHttpProviderConfig() { * @param value the value of the property * @return this instance of AsyncHttpProviderConfig */ - public NettyAsyncHttpProviderConfig addProperty(String name, Object value) { - - if (name.equals(REUSE_ADDRESS)// - && value == Boolean.TRUE// - && System.getProperty("os.name").toLowerCase().contains("win")) { - LOGGER.warn("Can't enable {} on Windows", REUSE_ADDRESS); - } else { - properties.put(name, value); - } + public NettyAsyncHttpProviderConfig addProperty(ChannelOption name, Object value) { + properties.put(name, value); + return this; + } + @SuppressWarnings("unchecked") + public NettyAsyncHttpProviderConfig addChannelOption(ChannelOption name, T value) { + properties.put((ChannelOption) name, value); return this; } @@ -127,7 +65,7 @@ public NettyAsyncHttpProviderConfig addProperty(String name, Object value) { * @param name * @return this instance of AsyncHttpProviderConfig */ - public Object getProperty(String name) { + public Object getProperty(ChannelOption name) { return properties.get(name); } @@ -137,7 +75,7 @@ public Object getProperty(String name) { * @param name * @return true if removed */ - public Object removeProperty(String name) { + public Object removeProperty(ChannelOption name) { return properties.remove(name); } @@ -146,40 +84,79 @@ public Object removeProperty(String name) { * * @return a the curent entry set. */ - public Set> propertiesSet() { + public Set, Object>> propertiesSet() { return properties.entrySet(); } - public EventLoopGroup getEventLoopGroup() { - return eventLoopGroup; - } + public static interface AdditionalChannelInitializer { - public void setEventLoopGroup(EventLoopGroup eventLoopGroup) { - this.eventLoopGroup = eventLoopGroup; + void initChannel(Channel ch) throws Exception; } - public int getMaxInitialLineLength() { - return maxInitialLineLength; - } + public static interface ResponseBodyPartFactory { - public void setMaxInitialLineLength(int maxInitialLineLength) { - this.maxInitialLineLength = maxInitialLineLength; + NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last); } - public int getMaxHeaderSize() { - return maxHeaderSize; + public static class EagerResponseBodyPartFactory implements ResponseBodyPartFactory { + + @Override + public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { + return new EagerResponseBodyPart(buf, last); + } } - public void setMaxHeaderSize(int maxHeaderSize) { - this.maxHeaderSize = maxHeaderSize; + public static class LazyResponseBodyPartFactory implements ResponseBodyPartFactory { + + @Override + public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { + return new LazyResponseBodyPart(buf, last); + } } - public int getMaxChunkSize() { - return maxChunkSize; + /** + * Allow configuring the Netty's event loop. + */ + private EventLoopGroup eventLoopGroup; + + private AdditionalChannelInitializer httpAdditionalChannelInitializer; + private AdditionalChannelInitializer wsAdditionalChannelInitializer; + private AdditionalChannelInitializer httpsAdditionalChannelInitializer; + private AdditionalChannelInitializer wssAdditionalChannelInitializer; + + /** + * HttpClientCodec's maxInitialLineLength + */ + private int maxInitialLineLength = 4096; + + /** + * HttpClientCodec's maxHeaderSize + */ + private int maxHeaderSize = 8192; + + /** + * HttpClientCodec's maxChunkSize + */ + private int maxChunkSize = 8192; + + private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); + + private ChannelPool channelPool; + + private boolean disableZeroCopy; + + private Timer nettyTimer; + + private long handshakeTimeoutInMillis; + + private SSLEngineFactory sslEngineFactory; + + public EventLoopGroup getEventLoopGroup() { + return eventLoopGroup; } - public void setMaxChunkSize(int maxChunkSize) { - this.maxChunkSize = maxChunkSize; + public void setEventLoopGroup(EventLoopGroup eventLoopGroup) { + this.eventLoopGroup = eventLoopGroup; } public AdditionalChannelInitializer getHttpAdditionalChannelInitializer() { @@ -214,6 +191,30 @@ public void setWssAdditionalChannelInitializer(AdditionalChannelInitializer wssA this.wssAdditionalChannelInitializer = wssAdditionalChannelInitializer; } + public int getMaxInitialLineLength() { + return maxInitialLineLength; + } + + public void setMaxInitialLineLength(int maxInitialLineLength) { + this.maxInitialLineLength = maxInitialLineLength; + } + + public int getMaxHeaderSize() { + return maxHeaderSize; + } + + public void setMaxHeaderSize(int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + } + + public int getMaxChunkSize() { + return maxChunkSize; + } + + public void setMaxChunkSize(int maxChunkSize) { + this.maxChunkSize = maxChunkSize; + } + public ResponseBodyPartFactory getBodyPartFactory() { return bodyPartFactory; } @@ -253,7 +254,7 @@ public long getHandshakeTimeoutInMillis() { public void setHandshakeTimeoutInMillis(long handshakeTimeoutInMillis) { this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; } - + public SSLEngineFactory getSslEngineFactory() { return sslEngineFactory; } @@ -261,30 +262,4 @@ public SSLEngineFactory getSslEngineFactory() { public void setSslEngineFactory(SSLEngineFactory sslEngineFactory) { this.sslEngineFactory = sslEngineFactory; } - - public static interface AdditionalChannelInitializer { - - void initChannel(Channel ch) throws Exception; - } - - public static interface ResponseBodyPartFactory { - - NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last); - } - - public static class EagerResponseBodyPartFactory implements ResponseBodyPartFactory { - - @Override - public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new EagerResponseBodyPart(buf, last); - } - } - - public static class LazyResponseBodyPartFactory implements ResponseBodyPartFactory { - - @Override - public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new LazyResponseBodyPart(buf, last); - } - } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 34f9338bf7..1c1eb6ed04 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -63,10 +63,7 @@ import javax.net.ssl.SSLEngine; import java.io.IOException; -import java.lang.reflect.Field; import java.security.GeneralSecurityException; -import java.util.HashMap; -import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -162,31 +159,13 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig freeConnections = null; } - Map> optionMap = new HashMap>(); - for (Field field : ChannelOption.class.getDeclaredFields()) { - if (field.getType().isAssignableFrom(ChannelOption.class)) { - field.setAccessible(true); - try { - optionMap.put(field.getName(), (ChannelOption) field.get(null)); - } catch (IllegalAccessException ex) { - throw new Error(ex); - } - } - } - - if (nettyProviderConfig != null) { - for (Entry entry : nettyProviderConfig.propertiesSet()) { - ChannelOption key = optionMap.get(entry.getKey()); - if (key != null) { - Object value = entry.getValue(); - plainBootstrap.option(key, value); - webSocketBootstrap.option(key, value); - secureBootstrap.option(key, value); - secureWebSocketBootstrap.option(key, value); - } else { - throw new IllegalArgumentException("Unknown config property " + entry.getKey()); - } - } + for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { + ChannelOption key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.option(key, value); + webSocketBootstrap.option(key, value); + secureBootstrap.option(key, value); + secureWebSocketBootstrap.option(key, value); } int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java index eeb0008d6f..79c5112869 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncProviderBasicTest.java @@ -17,6 +17,8 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.async.AsyncProvidersBasicTest; +import io.netty.channel.ChannelOption; + public class NettyAsyncProviderBasicTest extends AsyncProvidersBasicTest { @Override @@ -26,9 +28,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override protected AsyncHttpProviderConfig getProviderConfig() { - final NettyAsyncHttpProviderConfig config = new NettyAsyncHttpProviderConfig(); - config.addProperty("TCP_NODELAY", true); - return config; + return new NettyAsyncHttpProviderConfig().addChannelOption(ChannelOption.TCP_NODELAY, Boolean.TRUE); } @Override From 226995db6e973ce7c4dd916f9b7bf97f94732e09 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 15:02:08 +0200 Subject: [PATCH 0138/2070] fix build --- .../extras/registry/AsyncHttpClientRegistryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java index ffd8afad0f..c4e94ed128 100644 --- a/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java +++ b/extras/registry/src/test/java/org/asynchttpclient/extras/registry/AsyncHttpClientRegistryTest.java @@ -38,7 +38,7 @@ public void setUp() { @BeforeClass public void setUpBeforeTest() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, "org.asynchttpclient.TestAsyncHttpClient"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_IMPL_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.TEST_CLIENT_CLASS_NAME); } @AfterClass @@ -100,14 +100,14 @@ public void testCustomAsyncHttpClientRegistry() { @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testNonExistentAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.NonExistentAsyncRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.NON_EXISTENT_CLIENT_CLASS_NAME); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } @Test(groups = "fast", expectedExceptions = AsyncHttpClientImplException.class) public void testBadAsyncHttpClientRegistry() { - System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, "org.asynchttpclient.BadAsyncHttpClientRegistry"); + System.setProperty(AsyncImplHelper.ASYNC_HTTP_CLIENT_REGISTRY_SYSTEM_PROPERTY, AbstractAsyncHttpClientFactoryTest.BAD_CLIENT_CLASS_NAME); AsyncHttpClientRegistryImpl.getInstance(); Assert.fail("Should never have reached here"); } From 442c1469709dff25016444bb2b74493b12d94fcf Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 11:49:17 -0700 Subject: [PATCH 0139/2070] [master] + rework the fix for the issue #525 https://github.com/AsyncHttpClient/async-http-client/pull/525 "Move the hostname verification to after the SSL handshake has completed" --- .../providers/grizzly/ConnectionManager.java | 68 ++++++------------- .../grizzly/GrizzlyAsyncHttpProvider.java | 7 +- .../grizzly/filters/SwitchingSSLFilter.java | 67 ++++++++++++++++-- 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index 3130f83f51..b83618df63 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.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. @@ -21,7 +21,6 @@ import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.Base64; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; @@ -30,19 +29,14 @@ import org.glassfish.grizzly.connectionpool.EndpointKey; import org.glassfish.grizzly.filterchain.FilterChainBuilder; 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 org.glassfish.grizzly.utils.IdleTimeoutFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; import java.io.IOException; -import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -52,6 +46,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import org.asynchttpclient.providers.grizzly.filters.SwitchingSSLFilter; public class ConnectionManager { @@ -66,15 +61,13 @@ public class ConnectionManager { private final FilterChainBuilder secureBuilder; private final FilterChainBuilder nonSecureBuilder; private final boolean asyncConnect; - private final SSLFilter sslFilter; // ------------------------------------------------------------ Constructors ConnectionManager(final GrizzlyAsyncHttpProvider provider,// final ConnectionPool connectionPool,// final FilterChainBuilder secureBuilder,// - final FilterChainBuilder nonSecureBuilder,// - final SSLFilter sslFilter) { + final FilterChainBuilder nonSecureBuilder) { this.provider = provider; final AsyncHttpClientConfig config = provider.getClientConfig(); @@ -95,18 +88,26 @@ public class ConnectionManager { AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); asyncConnect = providerConfig instanceof GrizzlyAsyncHttpProviderConfig ? GrizzlyAsyncHttpProviderConfig.class.cast(providerConfig) .isAsyncConnectMode() : false; - this.sslFilter = sslFilter; } // ---------------------------------------------------------- Public Methods public void doTrackedConnection(final Request request,// final GrizzlyResponseFuture requestFuture,// - final CompletionHandler connectHandler) throws IOException { + CompletionHandler completionHandler) throws IOException { final EndpointKey key = getEndPointKey(request, requestFuture.getProxyServer()); - CompletionHandler handler = wrapHandler(request, getVerifier(), connectHandler, sslFilter); + + final HostnameVerifier verifier = getVerifier(); + final UriComponents uri = request.getURI(); + + if (Utils.isSecure(uri) && verifier != null) { + completionHandler = + SwitchingSSLFilter.wrapWithHostnameVerifierHandler( + completionHandler, verifier, uri.getHost()); + } + if (asyncConnect) { - connectionPool.take(key, handler); + connectionPool.take(key, completionHandler); } else { IOException ioe = null; GrizzlyFuture future = connectionPool.take(key); @@ -114,18 +115,18 @@ public void doTrackedConnection(final Request request,// // No explicit timeout when calling get() here as the Grizzly // endpoint pool will time it out based on the connect timeout // setting. - handler.completed(future.get()); + completionHandler.completed(future.get()); } catch (CancellationException e) { - handler.cancelled(); + completionHandler.cancelled(); } catch (ExecutionException ee) { final Throwable cause = ee.getCause(); if (cause instanceof ConnectionPool.MaxCapacityException) { ioe = (IOException) cause; } else { - handler.failed(ee.getCause()); + completionHandler.failed(ee.getCause()); } } catch (Exception ie) { - handler.failed(ie); + completionHandler.failed(ie); } if (ioe != null) { throw ioe; @@ -144,37 +145,6 @@ public Connection obtainConnection(final Request request, final GrizzlyResponseF // --------------------------------------------------Package Private Methods - static CompletionHandler wrapHandler(final Request request, final HostnameVerifier verifier, - final CompletionHandler delegate, final SSLFilter sslFilter) { - final UriComponents uri = request.getURI(); - if (Utils.isSecure(uri) && verifier != null) { - SSLBaseFilter.HandshakeListener handshakeListener = new SSLBaseFilter.HandshakeListener() { - @Override - public void onStart(Connection connection) { - // do nothing - LOGGER.debug("SSL Handshake onStart: "); - } - - @Override - public void onComplete(Connection connection) { - sslFilter.removeHandshakeListener(this); - - final String host = uri.getHost(); - final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); - 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); - } - } - }; - sslFilter.addHandshakeListener(handshakeListener); - } - return delegate; - } - static void markConnectionAsDoNotCache(final Connection c) { DO_NOT_CACHE.set(c, Boolean.TRUE); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 2e1d77ee37..9d3151957a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -259,8 +259,9 @@ public void onTimeout(Connection connection) { } } final SSLEngineConfigurator configurator = new SSLEngineConfigurator(context, true, false, false); - final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator); - secure.add(filter); + final SwitchingSSLFilter sslFilter = new SwitchingSSLFilter(configurator); + secure.add(sslFilter); + GrizzlyAsyncHttpProviderConfig providerConfig = (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig(); boolean npnEnabled = NextProtoNegSupport.isEnabled(); @@ -335,7 +336,7 @@ public void onTimeout(Connection connection) { } else { pool = null; } - connectionManager = new ConnectionManager(this, pool, secure, nonSecure, filter); + connectionManager = new ConnectionManager(this, pool, secure, nonSecure); } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index 3085c950e8..c8075ca630 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.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. @@ -13,7 +13,15 @@ package org.asynchttpclient.providers.grizzly.filters; +import java.io.IOException; +import java.net.ConnectException; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSession; import org.asynchttpclient.providers.grizzly.filters.events.SSLSwitchingEvent; +import org.asynchttpclient.util.Base64; +import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.EmptyCompletionHandler; import org.glassfish.grizzly.Grizzly; @@ -25,11 +33,9 @@ import org.glassfish.grizzly.filterchain.NextAction; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.grizzly.ssl.SSLFilter; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLHandshakeException; - -import java.io.IOException; +import org.glassfish.grizzly.ssl.SSLUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * SSL Filter that may be present within the FilterChain and may be @@ -45,6 +51,8 @@ public final class SwitchingSSLFilter extends SSLFilter { private static final Attribute HANDSHAKE_ERROR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SwitchingSSLFilter.class .getName() + "-HANDSHAKE-ERROR"); + private final static Logger LOGGER = LoggerFactory.getLogger(SwitchingSSLFilter.class); + // ------------------------------------------------------------ Constructors public SwitchingSSLFilter(final SSLEngineConfigurator clientConfig) { @@ -161,4 +169,51 @@ private static void setError(final Connection c, Throwable t) { private static void enableRead(final Connection c) throws IOException { c.enableIOEvent(IOEvent.READ); } + + // ================= HostnameVerifier section ======================== + + public static CompletionHandler wrapWithHostnameVerifierHandler( + final CompletionHandler delegateCompletionHandler, + final HostnameVerifier verifier, final String host) { + + return new CompletionHandler() { + + public void cancelled() { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.cancelled(); + } + } + + public void failed(final Throwable throwable) { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.failed(throwable); + } + } + + public void completed(final Connection connection) { + 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.terminateSilently(); + + if (delegateCompletionHandler != null) { + IOException e = new ConnectException("Host name verification failed for host " + host); + delegateCompletionHandler.failed(e); + } + } else if (delegateCompletionHandler != null) { + delegateCompletionHandler.completed(connection); + } + } + + public void updated(final Connection connection) { + if (delegateCompletionHandler != null) { + delegateCompletionHandler.updated(connection); + } + } + }; + } } From f171c9a13a150824f0b4d898dcbc03ddd2af6e4a Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 12:08:15 -0700 Subject: [PATCH 0140/2070] [master] + rework (#2) the fix for the issue #525 https://github.com/AsyncHttpClient/async-http-client/pull/525 "Move the hostname verification to after the SSL handshake has completed" --- .../grizzly/filters/SwitchingSSLFilter.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java index c8075ca630..b0449e82d2 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/SwitchingSSLFilter.java @@ -191,20 +191,26 @@ public void failed(final Throwable throwable) { } public void completed(final Connection connection) { - 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 (getHandshakeError(connection) == null) { + 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.terminateSilently(); - if (!verifier.verify(host, session)) { - connection.terminateSilently(); - - if (delegateCompletionHandler != null) { - IOException e = new ConnectException("Host name verification failed for host " + host); - delegateCompletionHandler.failed(e); + if (delegateCompletionHandler != null) { + IOException e = new ConnectException("Host name verification failed for host " + host); + delegateCompletionHandler.failed(e); + } + + return; } - } else if (delegateCompletionHandler != null) { + } + + if (delegateCompletionHandler != null) { delegateCompletionHandler.completed(connection); } } From 4393106266c50f98d7b88b1092d4512d4dec60f1 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 23:40:43 -0700 Subject: [PATCH 0141/2070] [master] fix issue #608 https://github.com/AsyncHttpClient/async-http-client/issues/608 "Grizzly provider can't deal with wss + proxy" --- providers/grizzly/pom.xml | 2 +- .../filters/AsyncHttpClientFilter.java | 11 +++++--- .../grizzly/filters/ProxyFilter.java | 25 ++++++++++++------- .../websocket/GrizzlyProxyTunnellingTest.java | 5 ---- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/providers/grizzly/pom.xml b/providers/grizzly/pom.xml index b55f00865e..269aea00ba 100644 --- a/providers/grizzly/pom.xml +++ b/providers/grizzly/pom.xml @@ -14,7 +14,7 @@ - 2.3.14 + 2.3.16 1.1 diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index f1be2da91d..21dc88c516 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -469,10 +469,13 @@ private static boolean isWSRequest(final UriComponents requestUri) { private static void convertToUpgradeRequest(final HttpTxContext ctx) { - UriComponents originalUri = ctx.getRequestUri(); - String newScheme = originalUri.getScheme().equalsIgnoreCase("https") ? "wss" : "ws"; - ctx.setWsRequestURI(originalUri); - ctx.setRequestUri(originalUri.withNewScheme(newScheme)); + final UriComponents requestUri = ctx.getRequestUri(); + + ctx.setWsRequestURI(requestUri); + ctx.setRequestUri(requestUri.withNewScheme( + "ws".equals(requestUri.getScheme()) + ? "http" + : "https")); } private void addGeneralHeaders(final Request request, final HttpRequestPacket requestPacket) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index f233d40e1f..ded8031daf 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.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. @@ -29,6 +29,7 @@ import org.glassfish.grizzly.http.util.Header; import java.io.IOException; +import org.glassfish.grizzly.http.HttpPacket; /** * This Filter will be placed in the FilterChain when a request is being @@ -56,15 +57,21 @@ public ProxyFilter(final ProxyServer proxyServer, final AsyncHttpClientConfig co @Override public NextAction handleWrite(FilterChainContext ctx) throws IOException { - org.glassfish.grizzly.http.HttpContent content = ctx.getMessage(); - HttpRequestPacket request = (HttpRequestPacket) content.getHttpHeader(); - HttpTxContext context = HttpTxContext.get(ctx); - assert (context != null); - Request req = context.getRequest(); - if (!secure) { - request.setRequestURI(req.getURI().toUrl()); + final Object msg = ctx.getMessage(); + if (HttpPacket.isHttp(msg)) { + HttpPacket httpPacket = (HttpPacket) msg; + final HttpRequestPacket request = (HttpRequestPacket) httpPacket.getHttpHeader(); + if (!request.isCommitted()) { + HttpTxContext context = HttpTxContext.get(ctx); + assert (context != null); + Request req = context.getRequest(); + if (!secure) { + request.setRequestURI(req.getURI().toUrl()); + } + addProxyHeaders(getRealm(req), request); + } } - addProxyHeaders(getRealm(req), request); + return ctx.getInvokeAction(); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java index 6d69758e71..0d864e1fc2 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/websocket/GrizzlyProxyTunnellingTest.java @@ -25,9 +25,4 @@ public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return GrizzlyProviderUtil.grizzlyProvider(config); } - - @Test(timeOut = 60000, enabled = false) - public void echoText() throws Exception { - // FIXME - } } From ee3f56dad3c15d40cc8df7a0c96b0daab45073d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 22:55:44 +0200 Subject: [PATCH 0142/2070] Refactor Netty channel pool, port #624 on master, close #201, close #623 --- .../netty/NettyAsyncHttpProvider.java | 13 +- .../netty/NettyAsyncHttpProviderConfig.java | 2 +- .../netty/channel/ChannelManager.java | 168 ++++++++++++++++++ .../providers/netty/channel/Channels.java | 156 ++++++---------- .../netty/channel/{ => pool}/ChannelPool.java | 30 ++-- .../{ => pool}/DefaultChannelPool.java | 136 ++++++-------- .../NoopChannelPool.java} | 12 +- .../providers/netty/handler/HttpProtocol.java | 20 +-- .../providers/netty/handler/Processor.java | 2 +- .../providers/netty/handler/Protocol.java | 12 +- .../netty/request/NettyConnectListener.java | 48 ++++- .../netty/request/NettyRequestSender.java | 93 +++++----- .../netty/NettyConnectionPoolTest.java | 18 +- 13 files changed, 401 insertions(+), 309 deletions(-) create mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{ => pool}/ChannelPool.java (55%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{ => pool}/DefaultChannelPool.java (68%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/{NonChannelPool.java => pool/NoopChannelPool.java} (73%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java index 01d71e1baf..5fb2104212 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -32,7 +32,6 @@ public class NettyAsyncHttpProvider implements AsyncHttpProvider { private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); - private final AsyncHttpClientConfig config; private final NettyAsyncHttpProviderConfig nettyConfig; private final AtomicBoolean closed = new AtomicBoolean(false); private final Channels channels; @@ -40,9 +39,8 @@ public class NettyAsyncHttpProvider implements AsyncHttpProvider { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { - this.config = config; nettyConfig = config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig ? // - NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()) + (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig() : new NettyAsyncHttpProviderConfig(); channels = new Channels(config, nettyConfig); @@ -50,15 +48,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { channels.configureProcessor(requestSender, closed); } - @Override - public String toString() { - int availablePermits = channels.freeConnections != null ? channels.freeConnections.availablePermits() : 0; - return String.format("NettyAsyncHttpProvider4:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s", - config.getMaxTotalConnections() - availablePermits,// - channels.openChannels.toString(),// - channels.channelPool.toString()); - } - @Override public void close() { if (closed.compareAndSet(false, true)) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index b03b6ef31b..554e1643c1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -18,7 +18,7 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.SSLEngineFactory; -import org.asynchttpclient.providers.netty.channel.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java new file mode 100644 index 0000000000..637a619c6f --- /dev/null +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -0,0 +1,168 @@ +/* + * 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 org.asynchttpclient.providers.netty.channel; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.channel.Channel; +import io.netty.channel.group.ChannelGroup; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; + +public class ChannelManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); + + private final ChannelPool channelPool; + 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 channel2KeyPool; + + public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + 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) { + freeChannels.release(); + if (maxConnectionsPerHostEnabled) { + String poolKey = channel2KeyPool.remove(Channel.class.cast(o)); + if (poolKey != null) { + Semaphore freeChannelsForHost = freeChannelsPerHost.get(poolKey); + if (freeChannelsForHost != null) + freeChannelsForHost.release(); + } + } + } + return removed; + } + }; + freeChannels = new Semaphore(config.getMaxTotalConnections()); + } else { + openChannels = new CleanupChannelGroup("asyncHttpClient"); + freeChannels = null; + } + + maxConnectionsPerHost = config.getMaxConnectionPerHost(); + maxConnectionsPerHostEnabled = config.getMaxConnectionPerHost() > 0; + + if (maxConnectionsPerHostEnabled) { + freeChannelsPerHost = new ConcurrentHashMap(); + channel2KeyPool = new ConcurrentHashMap(); + } else { + freeChannelsPerHost = null; + channel2KeyPool = null; + } + } + + public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { + if (keepAlive && channel.isActive()) { + LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); + channelPool.offer(channel, poolKey); + if (maxConnectionsPerHostEnabled) + channel2KeyPool.putIfAbsent(channel, poolKey); + Channels.setDiscard(channel); + } else { + // not offered + closeChannel(channel); + } + } + + public Channel poll(String uri) { + return channelPool.poll(uri); + } + + public boolean removeAll(Channel connection) { + return channelPool.removeAll(connection); + } + + 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) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + future.cancelTimeouts(); + } + } + } + + 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) { + LOGGER.debug("Closing Channel {} ", channel); + try { + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Error closing a connection", t); + } + openChannels.remove(channel); + } + } + + public void abortChannelPreemption(String poolKey) { + if (maxTotalConnectionsEnabled) + freeChannels.release(); + if (maxConnectionsPerHostEnabled) + getFreeConnectionsForHost(poolKey).release(); + } + + public void registerOpenChannel(Channel channel) { + openChannels.add(channel); + } +} \ No newline at end of file diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 1c1eb6ed04..3dfc57f9be 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -25,13 +25,14 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.DiscardEvent; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.handler.Processor; import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; import org.asynchttpclient.uri.UriComponents; import org.asynchttpclient.util.SslUtils; import org.slf4j.Logger; @@ -43,7 +44,6 @@ import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; -import io.netty.channel.group.ChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.HttpClientCodec; @@ -65,7 +65,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Map.Entry; -import java.util.concurrent.Semaphore; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -95,20 +95,7 @@ public class Channels { private final Bootstrap webSocketBootstrap; private final Bootstrap secureWebSocketBootstrap; - public final ChannelPool channelPool; - public final Semaphore freeConnections; - public final boolean trackConnections; - public final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { - @Override - public boolean remove(Object o) { - boolean removed = super.remove(o); - if (removed && trackConnections) { - freeConnections.release(); - } - return removed; - } - }; - + public final ChannelManager channelManager; private final boolean allowStopNettyTimer; private final Timer nettyTimer; private final long handshakeTimeoutInMillis; @@ -147,17 +134,10 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig if (config.isAllowPoolingConnection()) { cp = new DefaultChannelPool(config, nettyTimer); } else { - cp = new NonChannelPool(); + cp = new NoopChannelPool(); } } - this.channelPool = cp; - if (config.getMaxTotalConnections() != -1) { - trackConnections = true; - freeConnections = new Semaphore(config.getMaxTotalConnections()); - } else { - trackConnections = false; - freeConnections = null; - } + this.channelManager = new ChannelManager(config, cp); for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { ChannelOption key = entry.getKey(); @@ -182,11 +162,11 @@ private Timer newNettyTimer() { } public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { - + SSLEngine sslEngine = null; if (nettyProviderConfig.getSslEngineFactory() != null) { sslEngine = nettyProviderConfig.getSslEngineFactory().newSSLEngine(); - + } else { SSLContext sslContext = config.getSSLContext(); if (sslContext == null) @@ -195,11 +175,11 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep sslEngine = sslContext.createSSLEngine(peerHost, peerPort); sslEngine.setUseClientMode(true); } - + SslHandler sslHandler = new SslHandler(sslEngine); if (handshakeTimeoutInMillis > 0) sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); - + return sslHandler; } @@ -244,8 +224,7 @@ protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this)) - .addLast(HTTP_HANDLER, newHttpClientCodec()); + .addLast(SSL_HANDLER, new SslInitializer(Channels.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); if (config.isCompressionEnabled()) { pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); @@ -281,15 +260,7 @@ public Bootstrap getBootstrap(UriComponents uri, boolean useSSl, boolean useProx } public void close() { - channelPool.destroy(); - for (Channel channel : openChannels) { - Object attribute = getDefaultAttribute(channel); - if (attribute instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attribute; - future.cancelTimeouts(); - } - } - openChannels.close(); + channelManager.destroy(); if (allowReleaseEventLoopGroup) eventLoopGroup.shutdownGracefully(); @@ -354,7 +325,7 @@ public static void upgradePipelineForWebSockets(Channel channel) { } public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - final Channel channel = channelPool.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); + final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); if (channel != null) { LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -368,82 +339,48 @@ public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, return channel; } - public boolean acquireConnection(AsyncHandler asyncHandler) throws IOException { + public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { - if (!channelPool.canCacheConnection()) { - IOException ex = new IOException("Too many connections " + config.getMaxTotalConnections()); + boolean channelPreempted = false; + if (channelManager.preemptChannel(poolKey)) { + channelPreempted = 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()) { - return true; - } else { - IOException ex = new IOException("Too many connections " + config.getMaxTotalConnections()); - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("!connectionsPool.canCacheConnection()", t); - } - throw ex; - } - } - - return false; - } - - public void registerChannel(Channel channel) { - openChannels.add(channel); - } - - public boolean offerToPool(String key, Channel channel) { - return channelPool.offer(key, channel); + return channelPreempted; } - public void releaseFreeConnections() { - freeConnections.release(); + public void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); } - public void removeFromPool(Channel channel) { - channelPool.removeAll(channel); + public void abortChannelPreemption(String poolKey) { + channelManager.abortChannelPreemption(poolKey); } public void closeChannel(Channel channel) { - removeFromPool(channel); - finishChannel(channel); + channelManager.closeChannel(channel); } - public void finishChannel(Channel channel) { - setDefaultAttribute(channel, DiscardEvent.INSTANCE); - - // The channel may have already been removed if a timeout occurred, and - // this method may be called just after. - if (channel == null) - return; - - LOGGER.debug("Closing Channel {} ", channel); - try { - channel.close(); - } catch (Throwable t) { - LOGGER.debug("Error closing a connection", t); - } + public final Callable> newDrainCallable(final NettyResponseFuture future, final Channel channel, + final boolean keepAlive, final String poolKey) { - openChannels.remove(channel); + return new Callable>() { + public NettyResponseFuture call() throws Exception { + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); + return null; + } + }; } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - setDefaultAttribute(channel, new Callback(future) { - public void call() throws Exception { - if (!(future.isKeepAlive() && channel.isActive() && channelPool.offer(getPoolKey(future), channel))) { - finishChannel(channel); - } - } - }); + setDefaultAttribute(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); } public String getPoolKey(NettyResponseFuture future) { @@ -451,17 +388,16 @@ public String getPoolKey(NettyResponseFuture future) { } public void removeAll(Channel channel) { - channelPool.removeAll(channel); + channelManager.removeAll(channel); } public void abort(NettyResponseFuture future, Throwable t) { + Channel channel = future.channel(); - if (channel != null && openChannels.contains(channel)) { - closeChannel(channel); - openChannels.remove(channel); - } + if (channel != null) + channelManager.closeChannel(channel); - if (!future.isCancelled() && !future.isDone()) { + if (!future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), t); } @@ -485,4 +421,12 @@ public static Object getDefaultAttribute(Channel channel) { public static void setDefaultAttribute(Channel channel, Object o) { channel.attr(DEFAULT_ATTRIBUTE).set(o); } + + public static void setDiscard(Channel channel) { + setDefaultAttribute(channel, DiscardEvent.INSTANCE); + } + + public void registerOpenChannel(Channel channel) { + channelManager.registerOpenChannel(channel); + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java similarity index 55% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java index 39f5c7a5af..4f1d96ba16 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java @@ -14,47 +14,47 @@ * under the License. * */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import io.netty.channel.Channel; public interface ChannelPool { /** - * Add a connection to the pool + * Add a channel to the pool * - * @param uri a uri used to retrieve the cached connection - * @param connection an I/O connection + * @param poolKey a key used to retrieve the cached channel + * @param channel an I/O channel * @return true if added. */ - boolean offer(String uri, Channel connection); + boolean offer(Channel channel, String poolKey); /** - * Remove the connection associated with the uri. + * Remove the channel associated with the uri. * * @param uri the uri used when invoking addConnection - * @return the connection associated with the uri + * @return the channel associated with the uri */ Channel poll(String uri); /** - * Remove all connections from the cache. A connection might have been associated with several uri. + * Remove all channels from the cache. A channel might have been associated with several uri. * - * @param connection a connection - * @return the true if the connection has been removed + * @param channel a channel + * @return the true if the channel has been removed */ - boolean removeAll(Channel connection); + boolean removeAll(Channel channel); /** - * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching + * Return true if a channel 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. + * @return true if a channel can be cached. */ - boolean canCacheConnection(); + boolean isOpen(); /** - * Destroy all connections that has been cached by this instance. + * Destroy all channels that has been cached by this instance. */ void destroy(); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java similarity index 68% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index a1c1c9f4ed..f46a63d310 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -1,21 +1,22 @@ /* - * 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. */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,33 +25,27 @@ import io.netty.util.Timeout; import io.netty.util.Timer; import io.netty.util.TimerTask; -import io.netty.util.internal.chmv8.ConcurrentHashMapV8; 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; /** - * A simple implementation of {@link 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 class DefaultChannelPool implements ChannelPool { +public final class DefaultChannelPool implements ChannelPool { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); - private final ConcurrentHashMapV8> connectionsPool = new ConcurrentHashMapV8>(); - private final ConcurrentHashMapV8 channel2Creation = new ConcurrentHashMapV8(); - private final AtomicInteger size = new AtomicInteger(); + private final ConcurrentHashMap> poolsPerKey = new ConcurrentHashMap>(); + private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); 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 +53,7 @@ public 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 +61,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; @@ -97,11 +86,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; } } @@ -137,7 +126,7 @@ private boolean isTTLExpired(Channel channel, long now) { } private boolean isRemotelyClosed(Channel channel) { - return !channel.isOpen(); + return !channel.isActive(); } private final class IdleChannelDetector implements TimerTask { @@ -163,12 +152,10 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - boolean closeable = true; Object attachment = Channels.getDefaultAttribute(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; @@ -204,23 +191,23 @@ 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 totalCount = size.get(); 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 - List candidateExpiredChannels = expiredChannels(pool, start); - List closedChannels = closeChannels(candidateExpiredChannels); + if (LOGGER.isDebugEnabled()) + totalCount += pool.size(); + + List closedChannels = closeChannels(expiredChannels(pool, start)); pool.removeAll(closedChannels); int poolClosedCount = closedChannels.size(); - size.addAndGet(-poolClosedCount); closedCount += poolClosedCount; } @@ -236,22 +223,23 @@ 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); + 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; } - LOGGER.debug("Maximum number of requests per key reached {} for {}", maxConnectionPerHost, key); - return false; + 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(); @@ -259,19 +247,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 = addIdleChannel(idleConnectionForKey, key, channel, now); - if (added) { - size.incrementAndGet(); - channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); - } + boolean added = getPoolForKey(poolKey).add(new IdleChannel(channel, now)); + if (added) + channel2Creation.putIfAbsent(channel, new ChannelCreation(now, poolKey)); return added; } @@ -279,12 +257,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(); @@ -298,11 +276,7 @@ else if (isRemotelyClosed(idleChannel.channel)) { } } } - if (idleChannel != null) { - size.decrementAndGet(); - return idleChannel.channel; - } else - return null; + return idleChannel != null ? idleChannel.channel : null; } /** @@ -310,16 +284,14 @@ else if (isRemotelyClosed(idleChannel.channel)) { */ public boolean removeAll(Channel channel) { ChannelCreation creation = channel2Creation.remove(channel); - return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); + return !isClosed.get() && creation != null && poolsPerKey.get(creation.poolKey).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); + public boolean isOpen() { + return !isClosed.get(); } /** @@ -329,27 +301,23 @@ 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(); + poolsPerKey.clear(); channel2Creation.clear(); - size.set(0); } private void close(Channel channel) { try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + // FIXME pity to have to do this here + Channels.setDiscard(channel); channel2Creation.remove(channel); channel.close(); } catch (Throwable t) { // noop } } - - public String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); - } -} +} \ No newline at end of file diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java similarity index 73% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java index c3a929ba24..f8d684ad84 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/NonChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java @@ -13,25 +13,25 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.asynchttpclient.providers.netty.channel; +package org.asynchttpclient.providers.netty.channel.pool; import io.netty.channel.Channel; -public class NonChannelPool implements ChannelPool { +public class NoopChannelPool implements ChannelPool { - public boolean offer(String uri, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return false; } - public Channel poll(String uri) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 9bd2b36ee9..377dd130cd 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -168,16 +168,13 @@ private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsens } } - private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean lastValidChunk) throws IOException { - if (lastValidChunk && future.isKeepAlive()) { + private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { + + boolean keepAlive = future.isKeepAlive(); + if (expectOtherChunks && keepAlive) channels.drainChannel(channel, future); - } else { - if (future.isKeepAlive() && channel.isActive() && channels.offerToPool(channels.getPoolKey(future), channel)) { - markAsDone(future, channel); - return; - } - channels.finishChannel(channel); - } + else + channels.tryToOfferChannelToPool(channel, keepAlive, channels.getPoolKey(future)); markAsDone(future, channel); } @@ -383,11 +380,12 @@ private boolean handleResponseAndExit(final Channel channel, final NettyResponse @Override public void handle(final Channel channel, final NettyResponseFuture future, final Object e) throws Exception { + future.touch(); // The connect timeout occurred. - if (future.isCancelled() || future.isDone()) { - channels.finishChannel(channel); + if (future.isDone()) { + channels.closeChannel(channel); return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 9d31b94d36..7c69daeba7 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -115,7 +115,7 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { } Channel channel = ctx.channel(); - channels.removeFromPool(channel); + channels.removeAll(channel); Object attachment = Channels.getDefaultAttribute(channel); LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 0c482212df..59ff36c90e 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -32,7 +32,6 @@ import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; @@ -50,6 +49,7 @@ import java.io.IOException; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; public abstract class Protocol { @@ -91,7 +91,7 @@ public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpP public abstract void onClose(Channel channel); - protected boolean handleRedirectAndExit(Request request, NettyResponseFuture future, HttpResponse response, final Channel channel) + protected boolean handleRedirectAndExit(Request request, final NettyResponseFuture future, HttpResponse response, final Channel channel) throws Exception { io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); @@ -147,13 +147,7 @@ protected boolean handleRedirectAndExit(Request request, NettyResponseFuture } } - Callback callback = new Callback(future) { - public void call() throws Exception { - if (!(initialConnectionKeepAlive && channel.isActive() && channels.offerToPool(initialPoolKey, channel))) { - channels.finishChannel(channel); - } - } - }; + Callable> callback = channels.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); if (HttpHeaders.isTransferEncodingChunked(response)) { // We must make sure there is no bytes left before diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 45f5ef4bfc..05b36fd230 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -47,15 +47,41 @@ final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyRequestSender requestSender; private final NettyResponseFuture future; - - public NettyConnectListener(AsyncHttpClientConfig config, NettyRequestSender requestSender, NettyResponseFuture future) { + private final Channels channels; + private final boolean channelPreempted; + private final String poolKey; + + public NettyConnectListener(AsyncHttpClientConfig config,// + NettyRequestSender requestSender,// + NettyResponseFuture future,// + Channels channels,// + boolean channelPreempted,// + String poolKey) { this.requestSender = requestSender; this.config = config; this.future = future; + this.channels = channels; + this.channelPreempted = channelPreempted; + this.poolKey = poolKey; + } + + private void abortChannelPreemption(String poolKey) { + if (channelPreempted) + channels.abortChannelPreemption(poolKey); } - public NettyResponseFuture future() { - return future; + private void writeRequest(Channel channel) { + + LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + + if (future.isDone()) { + abortChannelPreemption(poolKey); + return; + } + + channels.registerOpenChannel(channel); + future.attachChannel(channel, false); + requestSender.writeRequest(future, channel); } public void onFutureSuccess(final Channel channel) throws ConnectException { @@ -72,24 +98,28 @@ public void operationComplete(Future handshakeFuture) throws Ex SSLEngine engine = sslHandler.engine(); 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)) { + LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), + Base64.encode(session.getId()), session.isValid(), host); + if (hostnameVerifier.verify(host, session)) { + writeRequest(channel); + } else { + abortChannelPreemption(poolKey); ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); throw exception; - } else { - requestSender.writeRequest(future, channel); } } } }); } else { - requestSender.writeRequest(future, channel); + writeRequest(channel); } } public void onFutureFailure(Channel channel, Throwable cause) { + abortChannelPreemption(poolKey); + boolean canRetry = future.canRetry(); LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", channel, canRetry); if (canRetry// diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 2fdaab8d50..71bb2d1b1c 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -78,39 +78,40 @@ public NettyRequestSender(AtomicBoolean closed,// public boolean retry(NettyResponseFuture future, Channel channel) { - boolean success = false; + if (closed.get()) + return false; - if (!closed.get()) { - channels.removeAll(channel); + channels.removeAll(channel); - if (future == null) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; - } + if (future == null) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; + } - if (future != null && future.canBeReplayed()) { - future.setState(NettyResponseFuture.STATE.RECONNECTED); - future.getAndSetStatusReceived(false); + if (future != null && future.canBeReplayed()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); + future.getAndSetStatusReceived(false); - 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 { - sendNextRequest(future.getRequest(), future); - success = true; - } catch (IOException iox) { - future.setState(NettyResponseFuture.STATE.CLOSED); - future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); - } - } else { - LOGGER.debug("Unable to recover future {}\n", future); + try { + sendNextRequest(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; } - return success; } public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) @@ -218,35 +219,35 @@ 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? - boolean acquiredConnection = !reclaimCache && channels.acquireConnection(asyncHandler); Bootstrap bootstrap = channels.getBootstrap(request.getURI(), useSSl, useProxy); - NettyConnectListener connectListener = new NettyConnectListener(config, this, future); - ChannelFuture channelFuture; - try { - channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + boolean channelPreempted = false; + String poolKey = null; + + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { - } catch (Throwable t) { - if (acquiredConnection) { - channels.releaseFreeConnections(); - } - channels.abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); - return connectListener.future(); + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionPerHost() > 0) + poolKey = channels.getPoolKey(future); + + channelPreempted = channels.preemptChannel(asyncHandler, poolKey); } - channelFuture.addListener(connectListener); + try { + ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + channelFuture.addListener(new NettyConnectListener(config, this, future, channels, channelPreempted, poolKey)); - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest().getHttpRequest(), - channelFuture.channel()); + } catch (Throwable t) { + if (channelPreempted) + channels.abortChannelPreemption(poolKey); - if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { - channels.registerChannel(channelFuture.channel()); - connectListener.future().attachChannel(channelFuture.channel(), false); - } else if (acquiredConnection) { - channels.releaseFreeConnections(); + channels.abort(future, t.getCause() == null ? t : t.getCause()); } - return connectListener.future(); + + return future; } private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java index 156aeb9699..ea3f0d573c 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyConnectionPoolTest.java @@ -19,7 +19,7 @@ import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; import org.asynchttpclient.async.ConnectionPoolTest; -import org.asynchttpclient.providers.netty.channel.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; import org.testng.annotations.Test; import io.netty.channel.Channel; @@ -38,19 +38,19 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { public void testInvalidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return false; } - public Channel poll(String connection) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return false; } @@ -82,19 +82,19 @@ public void destroy() { public void testValidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel channel, String poolKey) { return true; } - public Channel poll(String connection) { + public Channel poll(String poolKey) { return null; } - public boolean removeAll(Channel connection) { + public boolean removeAll(Channel channel) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } From 6be39c58d044680bad36e2619e82ca9eb266be84 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 01:35:36 +0200 Subject: [PATCH 0143/2070] Properly compute Realm URI, close #626 --- .../java/org/asynchttpclient/util/AuthenticatorUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index a74d71a659..594eafa1a3 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -12,6 +12,7 @@ */ package org.asynchttpclient.util; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import org.asynchttpclient.ProxyServer; @@ -37,12 +38,11 @@ private static String computeRealmURI(Realm realm) { return "/"; } else { UriComponents uri = realm.getUri(); - 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 = uri.getPath(); - return omitQuery ? path : path + "?" + uri.getQuery(); + String path = getNonEmptyPath(uri); + return realm.isOmitQuery() || !MiscUtils.isNonEmpty(uri.getQuery()) ? path : path + "?" + uri.getQuery(); } } } From e9452c3b3ccbb27e6450093801d08f22123dc304 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 02:08:19 +0200 Subject: [PATCH 0144/2070] Make ThrottleRequestFilter properly release Semaphore, close #567 --- .../extra/AsyncHandlerWrapper.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java index c9b2f0ae7b..3ce9527270 100644 --- a/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java +++ b/api/src/main/java/org/asynchttpclient/extra/AsyncHandlerWrapper.java @@ -8,18 +8,27 @@ import org.slf4j.LoggerFactory; import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; public class AsyncHandlerWrapper implements AsyncHandler { - private final static Logger logger = LoggerFactory.getLogger(AsyncHandlerWrapper.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncHandlerWrapper.class); private final AsyncHandler asyncHandler; private final Semaphore available; + private final AtomicBoolean complete = new AtomicBoolean(false); public AsyncHandlerWrapper(AsyncHandler asyncHandler, Semaphore available) { this.asyncHandler = asyncHandler; this.available = available; } + private void complete() { + if (complete.compareAndSet(false, true)) + available.release(); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); + } + /** * {@inheritDoc} */ @@ -28,10 +37,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(); } } @@ -64,10 +70,10 @@ 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(); } -} \ No newline at end of file +} From baeb431b22ba1ccc83ee21218c46810d7633cad4 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 16 Jul 2014 21:44:31 -0700 Subject: [PATCH 0145/2070] [master] + minor threads cleanup, use ioThreads config value, fix tests --- .../grizzly/GrizzlyAsyncHttpProvider.java | 19 +++++++++ .../providers/grizzly/Utils.java | 16 ++++++++ .../GrizzlyFeedableBodyGeneratorTest.java | 40 +++++++++---------- .../GrizzlyNoTransferEncodingTest.java | 14 +++---- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 9d3151957a..fa6a759e53 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -73,7 +73,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; import org.glassfish.grizzly.spdy.SpdyVersion; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -305,6 +307,23 @@ public void onTimeout(Connection connection) { secure.add(new WebSocketClientFilter()); clientTransport.getAsyncQueueIO().getWriter().setMaxPendingBytesPerConnection(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(Utils.discoverTestName("grizzly-ahc-kernel")) // uncomment for tests to track down the leaked threads + ); + if (providerConfig != null) { final TransportCustomizer customizer = (TransportCustomizer) providerConfig.getProperty(Property.TRANSPORT_CUSTOMIZER); if (customizer != null) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java index 4a4a434cca..8b7ae72a1a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/Utils.java @@ -84,4 +84,20 @@ public static boolean isSpdyConnection(final Connection c) { Boolean result = SPDY.get(c); return result != null ? result : false; } + + 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("org.asynchttpclient.async")) { + return "grizzly-kernel-" + + stackTrace[i].getClassName() + "." + stackTrace[i].getMethodName(); + } + } + } + + return defaultName; + } } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 9e6a500c63..1aac4fcfce 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -13,24 +13,6 @@ package org.asynchttpclient.providers.grizzly; -import org.asynchttpclient.AsyncCompletionHandler; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.RequestBuilder; -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; @@ -42,14 +24,30 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import org.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.DefaultAsyncHttpClient; +import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder; - +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 { @@ -67,7 +65,7 @@ public class GrizzlyFeedableBodyGeneratorTest { // ------------------------------------------------------------------- Setup - @BeforeTest + @BeforeMethod public void setup() throws Exception { generateTempFile(); server = new HttpServer(); @@ -91,7 +89,7 @@ public void setup() throws Exception { // --------------------------------------------------------------- Tear Down - @AfterTest + @AfterMethod public void tearDown() { if (!tempFile.delete()) { tempFile.deleteOnExit(); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index 8655f47753..ea02d5fc57 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java @@ -13,21 +13,21 @@ package org.asynchttpclient.providers.grizzly; -import org.asynchttpclient.AsyncHttpClient; -import org.asynchttpclient.AsyncHttpClientConfig; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.DefaultAsyncHttpClient; 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.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; public class GrizzlyNoTransferEncodingTest { private static final String TEST_MESSAGE = "Hello World!"; @@ -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 25bf191ea9faa5ef1fa092c9fe954117b193fa28 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 10:23:58 +0200 Subject: [PATCH 0146/2070] Drop requestCompressionLevel config parameter, close #627 --- .../AsyncHttpClientConfig.java | 35 ------------------- .../AsyncHttpClientConfigBean.java | 6 ---- .../AsyncHttpClientConfigDefaults.java | 5 --- .../SimpleAsyncHttpClient.java | 5 --- .../providers/netty/channel/Channels.java | 5 --- 5 files changed, 56 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 422f560af9..2668db7550 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -98,7 +98,6 @@ public class AsyncHttpClientConfig { protected List requestFilters; protected List responseFilters; protected List ioExceptionFilters; - protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; protected boolean disableUrlEncodingForBoundRequests; @@ -140,7 +139,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, // List requestFilters, // List responseFilters, // List ioExceptionFilters, // - int requestCompressionLevel, // int maxRequestRetry, // boolean allowSslConnectionCaching, // boolean disableUrlEncodingForBoundRequests, // @@ -174,7 +172,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; @@ -394,15 +391,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 * @@ -560,7 +548,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(); @@ -887,26 +874,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 times a request will be retried when an {@link java.io.IOException} occurs because of a Network exception. * @@ -1123,7 +1090,6 @@ public Builder(AsyncHttpClientConfig prototype) { responseFilters.addAll(prototype.getResponseFilters()); ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); - requestCompressionLevel = prototype.getRequestCompressionLevel(); disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); @@ -1188,7 +1154,6 @@ public Thread newThread(Runnable r) { requestFilters, // responseFilters, // ioExceptionFilters, // - requestCompressionLevel, // maxRequestRetry, // allowSslConnectionPool, // disableUrlEncodingForBoundRequests, // diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 6c677b075e..254d00403d 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -59,7 +59,6 @@ void configureDefaults() { userAgent = defaultUserAgent(); allowPoolingConnection = defaultAllowPoolingConnection(); useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - requestCompressionLevel = defaultRequestCompressionLevel(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); @@ -201,11 +200,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/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index fa05cec469..47af64f89b 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index d601d4d82c..ad739b546a 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -565,11 +565,6 @@ public Builder setSSLContext(final SSLContext sslContext) { return this; } - public Builder setRequestCompressionLevel(int requestCompressionLevel) { - configBuilder.setRequestCompressionLevel(requestCompressionLevel); - return this; - } - public Builder setRealmNtlmDomain(String domain) { realm().setNtlmDomain(domain); return this; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 3dfc57f9be..54376e29b1 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -107,11 +107,6 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig this.config = config; this.nettyProviderConfig = nettyProviderConfig; - // FIXME https://github.com/netty/netty/issues/2132 - if (config.getRequestCompressionLevel() > 0) { - LOGGER.warn("Request was enabled but Netty actually doesn't support this feature, see https://github.com/netty/netty/issues/2132"); - } - // check if external EventLoopGroup is defined allowReleaseEventLoopGroup = nettyProviderConfig.getEventLoopGroup() == null; eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyProviderConfig.getEventLoopGroup(); From 8f289c3a94009715bafc8e3c1ea0c12f0079bb2d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 12:39:28 +0200 Subject: [PATCH 0147/2070] Add missing Host header port when using a virtual host, close #632 --- .../netty/request/NettyRequestFactory.java | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index d777c9d1c6..0af2bddfc6 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -88,20 +88,9 @@ else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithS } } - private String hostHeader(Request request, UriComponents uri, Realm realm) { - - String hostHeader = null; - + private String hostHeader(Request request, UriComponents uri) { String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - - if (host != null) { - if (request.getVirtualHost() != null || uri.getPort() == -1) - hostHeader = host; - else - hostHeader = host + ":" + uri.getPort(); - } - - return hostHeader; + return uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { @@ -148,9 +137,6 @@ else if (request.getVirtualHost() != null) else host = uri.getHost(); - if (host == null) - host = "127.0.0.1"; - try { authorizationHeader = "Negotiate " + SpnegoEngine.instance().generateToken(host); } catch (Throwable e) { @@ -318,12 +304,11 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean httpRequest.headers().set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - - String hostHeader = hostHeader(request, uri, realm); + 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 From 2da66bf266376470e18db04e472989aea34321ed Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:11:07 +0200 Subject: [PATCH 0148/2070] Revert #632 --- .../providers/netty/request/NettyRequestFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 0af2bddfc6..55bbc81b85 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -90,7 +90,7 @@ else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithS private String hostHeader(Request request, UriComponents uri) { String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - return uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { From 2834f03eeb3ec91464139daa96643d58de873c92 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:23:01 +0200 Subject: [PATCH 0149/2070] NettyResponseFuture.get timeout shouldn't cancel http request, close #370 --- .../netty/future/NettyResponseFuture.java | 200 +++++++----------- .../netty/request/NettyRequestSender.java | 6 +- .../timeout/RequestTimeoutTimerTask.java | 8 +- 3 files changed, 90 insertions(+), 124 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 0af60186d3..e95e5bfff6 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -18,7 +18,6 @@ import static org.asynchttpclient.util.DateUtils.millisTime; import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ConnectionPoolKeyStrategy; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Request; @@ -54,14 +53,12 @@ */ public final class NettyResponseFuture extends AbstractListenableFuture { - private static final Logger logger = LoggerFactory.getLogger(NettyResponseFuture.class); - public static final String MAX_RETRY = "org.asynchttpclient.providers.netty.maxRetry"; + private static final Logger LOGGER = LoggerFactory.getLogger(NettyResponseFuture.class); public enum STATE { NEW, POOLED, RECONNECTED, CLOSED, } - private final int requestTimeoutInMs; private volatile boolean requestTimeoutReached; private volatile boolean idleConnectionTimeoutReached; private final long start = millisTime(); @@ -105,37 +102,22 @@ public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// NettyRequest nettyRequest,// - int requestTimeoutInMs,// - AsyncHttpClientConfig config,// + int maxRetry,// ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// ProxyServer proxyServer) { this.asyncHandler = asyncHandler; - this.requestTimeoutInMs = requestTimeoutInMs; this.request = request; this.nettyRequest = nettyRequest; this.uri = uri; this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; - - maxRetry = Integer.getInteger(MAX_RETRY, config.getMaxRequestRetry()); - } - - public UriComponents getURI() { - return uri; - } - - public void setURI(UriComponents uri) { - this.uri = uri; + this.maxRetry = maxRetry; } - public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; - } - - public ProxyServer getProxyServer() { - return proxyServer; - } + /*********************************************/ + /** java.util.concurrent.Future **/ + /*********************************************/ @Override public boolean isDone() { @@ -147,10 +129,6 @@ public boolean isCancelled() { return isCancelled.get(); } - public void setAsyncHandler(AsyncHandler asyncHandler) { - this.asyncHandler = asyncHandler; - } - @Override public boolean cancel(boolean force) { cancelTimeouts(); @@ -168,7 +146,7 @@ public boolean cancel(boolean force) { try { asyncHandler.onThrowable(new CancellationException()); } catch (Throwable t) { - logger.warn("cancel", t); + LOGGER.warn("cancel", t); } } latch.countDown(); @@ -176,91 +154,22 @@ public boolean cancel(boolean force) { 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; - } - @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(); } @Override public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone() && !isCancelled()) { - boolean expired = false; - if (l == -1) { - latch.await(); - } else { - expired = !latch.await(l, tu); - } - - if (expired) { - isCancelled.set(true); - try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); - channel.close(); - } catch (Throwable t) { - // Ignore - } - TimeoutException te = new TimeoutException(String.format("No response received after %s %s", l, tu.name().toLowerCase())); - if (!onThrowableCalled.getAndSet(true)) { - try { - 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(); } private V getContent() throws ExecutionException { + // FIXME why lose the exception??? ExecutionException e = exEx.getAndSet(null); if (e != null) { throw e; @@ -278,7 +187,7 @@ private 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 { @@ -291,6 +200,10 @@ private V getContent() throws ExecutionException { return update; } + /*********************************************/ + /** org.asynchttpclient.ListenableFuture **/ + /*********************************************/ + public final void done() { try { @@ -325,13 +238,74 @@ 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(); runListeners(); } + @Override + public void touch() { + touch.set(millisTime()); + } + + /*********************************************/ + /** INTERNAL **/ + /*********************************************/ + + public UriComponents getURI() { + return uri; + } + + public void setURI(UriComponents uri) { + this.uri = uri; + } + + public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { + return connectionPoolKeyStrategy; + } + + public ProxyServer getProxyServer() { + return proxyServer; + } + + 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(); + timeoutsHolder = null; + } + } + public final Request getRequest() { return request; } @@ -408,11 +382,6 @@ public void setStreamWasAlreadyConsumed(boolean streamWasAlreadyConsumed) { this.streamWasAlreadyConsumed = streamWasAlreadyConsumed; } - @Override - public void touch() { - touch.set(millisTime()); - } - public long getLastTouch() { return touch.get(); } @@ -470,9 +439,9 @@ public boolean canRetry() { } public SocketAddress getChannelRemoteAddress() { - return channel() != null? channel().remoteAddress(): null; + return channel() != null ? channel().remoteAddress() : null; } - + public void setRequest(Request request) { this.request = request; } @@ -492,10 +461,6 @@ public long getStart() { return start; } - public long getRequestTimeoutInMs() { - return requestTimeoutInMs; - } - @Override public String toString() { return "NettyResponseFuture{" + // @@ -503,7 +468,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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 71bb2d1b1c..ff18a9d5b8 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -253,14 +253,12 @@ private ListenableFuture sendRequestWithNewChannel(// private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); NettyResponseFuture f = new NettyResponseFuture(// uri,// request,// asyncHandler,// nettyRequest,// - requestTimeout,// - config,// + config.getMaxRequestRetry(),// request.getConnectionPoolKeyStrategy(),// proxyServer); @@ -388,7 +386,7 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, - closed), requestTimeoutInMs); + closed, requestTimeoutInMs), requestTimeoutInMs); timeoutsHolder.requestTimeout = requestTimeout; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 13cae2eb43..cb4d2ca509 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -26,12 +26,16 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { + private final long requestTimeout; + public RequestTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// Channels channels,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed) { + AtomicBoolean clientClosed,// + long requestTimeout) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + this.requestTimeout = requestTimeout; } @Override @@ -45,7 +49,7 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - 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(); From 1196a96816d912ad4b454acb25a848fa0f9cdd86 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:45:19 +0200 Subject: [PATCH 0150/2070] NettyResponseFuture.getContent shouldn't lose registered exception, close #271 --- .../providers/netty/future/NettyResponseFuture.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index e95e5bfff6..f5078b1d21 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -169,16 +169,15 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } private 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 712c04aef1c0588ce1cff0e5d7ba9ba5a9569556 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 16:16:47 +0200 Subject: [PATCH 0151/2070] Make NettyResponseFuture done and abort mutually exclusive, close #247 --- .../providers/netty/future/NettyResponseFuture.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index f5078b1d21..1418c3c4a5 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -205,14 +205,14 @@ private V getContent() throws ExecutionException { public final void done() { - try { - cancelTimeouts(); + cancelTimeouts(); - if (exEx.get() != null) { - return; - } + if (isDone.getAndSet(true) || isCancelled.get()) + return; + + try { getContent(); - isDone.set(true); + } catch (ExecutionException t) { return; } catch (RuntimeException t) { @@ -227,6 +227,7 @@ public final void done() { } public final void abort(final Throwable t) { + cancelTimeouts(); if (isDone.get() || isCancelled.getAndSet(true)) From b06e0868826df349b8796800c453ec2d44259dd3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:13:24 +0200 Subject: [PATCH 0152/2070] Rename AsyncHttpClientConfig parameters, close #622 --- .../AsyncHttpClientConfig.java | 427 ++++++++---------- .../AsyncHttpClientConfigBean.java | 64 +-- .../AsyncHttpClientConfigDefaults.java | 38 +- .../SimpleAsyncHttpClient.java | 39 +- .../util/AsyncHttpProviderUtils.java | 4 +- .../async/AsyncProvidersBasicTest.java | 6 +- .../async/AuthTimeoutTest.java | 2 +- .../asynchttpclient/async/BasicAuthTest.java | 2 +- .../asynchttpclient/async/BasicHttpsTest.java | 4 +- .../asynchttpclient/async/BodyChunkTest.java | 6 +- .../async/BodyDeferringAsyncHandlerTest.java | 2 +- .../asynchttpclient/async/ChunkingTest.java | 8 +- .../async/ConnectionPoolTest.java | 8 +- .../async/FilePartLargeFileTest.java | 2 +- .../async/IdleStateHandlerTest.java | 2 +- .../async/MaxConnectionsInThreads.java | 4 +- .../async/MaxTotalConnectionTest.java | 6 +- .../async/NoNullResponseTest.java | 4 +- .../async/PerRequestTimeoutTest.java | 6 +- .../async/PutLargeFileTest.java | 2 +- .../org/asynchttpclient/async/RC10KTest.java | 2 +- .../async/RedirectConnectionUsageTest.java | 8 +- .../asynchttpclient/async/RemoteSiteTest.java | 16 +- .../async/SimpleAsyncHttpClientTest.java | 16 +- .../async/TransferListenerTest.java | 2 +- .../providers/grizzly/ConnectionManager.java | 10 +- .../providers/grizzly/EventHandler.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 +- .../grizzly/GrizzlyConnectionPoolTest.java | 4 +- .../GrizzlyFeedableBodyGeneratorTest.java | 4 +- .../GrizzlyNoTransferEncodingTest.java | 6 +- .../GrizzlyUnexpectingTimeoutTest.java | 2 +- .../netty/channel/ChannelManager.java | 16 +- .../providers/netty/channel/Channels.java | 6 +- .../channel/pool/DefaultChannelPool.java | 8 +- .../netty/request/NettyRequestSender.java | 8 +- .../NettyRequestThrottleTimeoutTest.java | 2 +- .../netty/RetryNonBlockingIssue.java | 16 +- 38 files changed, 360 insertions(+), 408 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 2668db7550..265008c2bb 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -34,24 +34,12 @@ import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; /** * Configuration class to use with a {@link AsyncHttpClient}. System property can be also used to configure this * object default behavior by doing: *

* -Dorg.asynchttpclient.AsyncHttpClientConfig.nameOfTheProperty - * ex: - *

- * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxTotalConnections - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxConnectionsPerHost - * -Dorg.asynchttpclient.AsyncHttpClientConfig.connectionTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.idleConnectionInPoolTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.requestTimeoutInMs - * -Dorg.asynchttpclient.AsyncHttpClientConfig.redirectsEnabled - * -Dorg.asynchttpclient.AsyncHttpClientConfig.maxRedirects */ public class AsyncHttpClientConfig { @@ -78,115 +66,122 @@ public class AsyncHttpClientConfig { AHC_VERSION = prop.getProperty("ahc.version", "UNKNOWN"); } - 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 disableUrlEncodingForBoundRequests; - protected boolean removeQueryParamOnRedirect; - protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; - protected boolean strict302Handling; - protected int maxConnectionLifeTimeInMs; - protected boolean useRelativeURIsWithSSLProxies; + protected TimeConverter timeConverter; + protected AsyncHttpProviderConfig providerConfig; + + // AHC 2 specific protected boolean spdyEnabled; protected int spdyInitialWindowSize; protected int spdyMaxConcurrentStreams; - protected TimeConverter timeConverter; - protected boolean acceptAnyCertificate; protected AsyncHttpClientConfig() { } - private AsyncHttpClientConfig(int maxTotalConnections, // - int maxConnectionPerHost, // - int connectionTimeOutInMs, // - int webSocketTimeoutInMs, // - int idleConnectionInPoolTimeoutInMs, // - int idleConnectionTimeoutInMs, // - int requestTimeoutInMs, // - int 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 compressionEnabled, // - String userAgent, // - boolean keepAlive, // - ScheduledExecutorService reaper, // - ExecutorService applicationThreadPool, // + boolean removeQueryParamOnRedirect,// + boolean strict302Handling, // + ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // - SSLContext sslContext, // - SSLEngineFactory sslEngineFactory, // - AsyncHttpProviderConfig providerConfig, // - Realm realm, // - List requestFilters, // - List responseFilters, // - List ioExceptionFilters, // + boolean useRelativeURIsWithSSLProxies, // + boolean compressionEnabled, // + String userAgent,// + Realm realm,// + List requestFilters,// + List responseFilters,// + List ioExceptionFilters,// int maxRequestRetry, // - boolean allowSslConnectionCaching, // boolean disableUrlEncodingForBoundRequests, // - boolean removeQueryParamOnRedirect, // - HostnameVerifier hostnameVerifier, // int ioThreadMultiplier, // - boolean strict302Handling, // - boolean useRelativeURIsWithSSLProxies, // + TimeConverter timeConverter,// + AsyncHttpProviderConfig providerConfig,// boolean spdyEnabled, // int spdyInitialWindowSize, // - int spdyMaxConcurrentStreams, // - 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; + int spdyMaxConcurrentStreams) { + + 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; - this.applicationThreadPool = applicationThreadPool; - this.proxyServerSelector = proxyServerSelector; this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; + this.ioThreadMultiplier = ioThreadMultiplier; + this.timeConverter = timeConverter; + this.providerConfig = providerConfig; this.spdyEnabled = spdyEnabled; this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; - this.timeConverter = timeConverter; - this.acceptAnyCertificate = acceptAnyCertificate; } @@ -195,8 +190,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, // * * @return the maximum number of connections an {@link AsyncHttpClient} can handle. */ - public int getMaxTotalConnections() { - return maxTotalConnections; + public int getMaxConnections() { + return maxConnections; } /** @@ -204,8 +199,8 @@ public int getMaxTotalConnections() { * * @return the maximum number of connections per host an {@link AsyncHttpClient} can handle. */ - public int getMaxConnectionPerHost() { - return maxConnectionPerHost; + public int getMaxConnectionsPerHost() { + return maxConnectionsPerHost; } /** @@ -213,16 +208,16 @@ public int getMaxConnectionPerHost() { * * @return the maximum time in millisecond an {@link 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 org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketIdleTimeoutInMs() { - return webSocketIdleTimeoutInMs; + public int getWebSocketReadTimeout() { + return webSocketReadTimeout; } /** @@ -230,8 +225,8 @@ public int getWebSocketIdleTimeoutInMs() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle. */ - public int getIdleConnectionTimeoutInMs() { - return idleConnectionTimeoutInMs; + public int getReadTimeout() { + return readTimeout; } /** @@ -241,8 +236,8 @@ public int getIdleConnectionTimeoutInMs() { * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * in pool. */ - public int getIdleConnectionInPoolTimeoutInMs() { - return idleConnectionInPoolTimeoutInMs; + public int getPooledConnectionIdleTimeout() { + return pooledConnectionIdleTimeout; } /** @@ -250,8 +245,8 @@ public int getIdleConnectionInPoolTimeoutInMs() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} wait for a response */ - public int getRequestTimeoutInMs() { - return requestTimeoutInMs; + public int getRequestTimeout() { + return requestTimeout; } /** @@ -277,8 +272,8 @@ public int getMaxRedirects() { * * @return true if keep-alive is enabled */ - public boolean isAllowPoolingConnection() { - return allowPoolingConnection; + public boolean isAllowPoolingConnections() { + return allowPoolingConnections; } /** @@ -405,8 +400,8 @@ public int getMaxRequestRetry() { * * @return true is enabled. */ - public boolean isSslConnectionPoolEnabled() { - return allowSslConnectionPool; + public boolean isAllowPoolingSslConnections() { + return allowPoolingSslConnections; } /** @@ -511,8 +506,8 @@ public boolean isUseRelativeURIsWithSSLProxies() { * * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible. */ - public int getMaxConnectionLifeTimeInMs() { - return maxConnectionLifeTimeInMs; + public int getConnectionTTL() { + return connectionTTL; } /** @@ -532,103 +527,102 @@ 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 maxRedirects = 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 disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); - private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); - private boolean spdyEnabled = defaultSpdyEnabled(); - private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); - private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); - private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); - - private ScheduledExecutorService reaper; - private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; - private SSLContext sslContext; - private SSLEngineFactory sslEngineFactory; - 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 disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); + private int ioThreadMultiplier = defaultIoThreadMultiplier(); private TimeConverter timeConverter; - + private AsyncHttpProviderConfig providerConfig; + + // AHC 2 + private boolean spdyEnabled = defaultSpdyEnabled(); + private int spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + public Builder() { } /** * Set the maximum number of connections an {@link AsyncHttpClient} can handle. * - * @param maxTotalConnections the maximum number of connections an {@link AsyncHttpClient} can handle. + * @param maxConnections the maximum number of connections an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaxConnectionsTotal(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 AsyncHttpClient} can handle. * - * @param maxConnectionPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. + * @param maxConnectionsPerHost the maximum number of connections per host an {@link AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaxConnectionsPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) { + this.maxConnectionsPerHost = maxConnectionsPerHost; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host * - * @param connectionTimeOutInMs the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host + * @param connectionTimeout the maximum time in millisecond an {@link 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 org.asynchttpclient.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeoutInMs + * @param webSocketIdleTimeout * the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketIdleTimeoutInMs(int webSocketIdleTimeoutInMs) { - this.webSocketIdleTimeoutInMs = webSocketIdleTimeoutInMs; + public Builder setWebSocketReadTimeout(int webSocketReadTimeout) { + this.webSocketReadTimeout = webSocketReadTimeout; return this; } /** * Set the maximum time in millisecond an {@link AsyncHttpClient} can stay idle. * - * @param idleConnectionTimeoutInMs + * @param readTimeout * the maximum time in millisecond an {@link 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; } @@ -636,24 +630,24 @@ public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { * Set the maximum time in millisecond an {@link AsyncHttpClient} will keep connection * idle in pool. * - * @param idleConnectionInPoolTimeoutInMs + * @param pooledConnectionIdleTimeout * the maximum time in millisecond an {@link 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 AsyncHttpClient} wait for a response * - * @param requestTimeoutInMs the maximum time in millisecond an {@link AsyncHttpClient} wait for a response + * @param requestTimeout the maximum time in millisecond an {@link 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; } @@ -704,22 +698,11 @@ public Builder setUserAgent(String userAgent) { /** * 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} + * @param allowPoolingConnections true if connection can be pooled by a {@link ConnectionsPool} * @return a {@link Builder} */ - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = 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; + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + this.allowPoolingConnections = allowPoolingConnections; return this; } @@ -758,17 +741,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. * @@ -776,8 +748,6 @@ public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { * @return a {@link Builder} */ public Builder setSSLContext(final SSLContext sslContext) { - // reset previously set value so it will be lazily recreated - this.sslEngineFactory = null; this.sslContext = sslContext; return this; } @@ -888,11 +858,11 @@ public Builder setMaxRequestRetry(int maxRequestRetry) { /** * Return true is if connections pooling is enabled. * - * @param allowSslConnectionPool true if enabled + * @param pooledConnectionIdleTimeout true if enabled * @return this */ - public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + public Builder setAllowPoolingSslConnections(boolean allowPoolingSslConnections) { + this.allowPoolingSslConnections = allowPoolingSslConnections; return this; } @@ -982,11 +952,11 @@ public Builder setStrict302Handling(final boolean strict302Handling) { /** * 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; + public Builder setConnectionTTL(int connectionTTL) { + this.connectionTTL = connectionTTL; return this; } @@ -1064,18 +1034,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(); + connectionTimeout = prototype.getConnectionTimeout(); + pooledConnectionIdleTimeout = prototype.getPooledConnectionIdleTimeout(); + readTimeout = prototype.getReadTimeout(); + maxConnectionsPerHost = prototype.getMaxConnectionsPerHost(); + connectionTTL = prototype.getConnectionTTL(); maxRedirects = prototype.getMaxRedirects(); - maxTotalConnections = prototype.getMaxTotalConnections(); + maxConnections = prototype.getMaxConnections(); proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); - requestTimeoutInMs = prototype.getRequestTimeoutInMs(); + requestTimeout = prototype.getRequestTimeout(); sslContext = prototype.getSSLContext(); userAgent = prototype.getUserAgent(); followRedirect = prototype.isFollowRedirect(); @@ -1093,13 +1063,16 @@ public Builder(AsyncHttpClientConfig prototype) { disableUrlEncodingForBoundRequests = prototype.isDisableUrlEncodingForBoundRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); - allowSslConnectionPool = prototype.isAllowPoolingConnection(); + allowPoolingSslConnections = prototype.isAllowPoolingConnections(); removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); - useRelativeURIsWithSSLProxies = prototype.isUseRelativeURIsWithSSLProxies(); - timeConverter = prototype.getTimeConverter(); - acceptAnyCertificate = prototype.isAcceptAnyCertificate(); + timeConverter = prototype.timeConverter; + acceptAnyCertificate = prototype.acceptAnyCertificate; + + spdyEnabled = prototype.isSpdyEnabled(); + spdyInitialWindowSize = prototype.getSpdyInitialWindowSize(); + spdyMaxConcurrentStreams = prototype.getSpdyMaxConcurrentStreams(); } /** @@ -1109,16 +1082,6 @@ 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 (proxyServerSelector == null && useProxySelector) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } @@ -1131,42 +1094,40 @@ 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, // maxRedirects, // - compressionEnabled, // - userAgent, // - allowPoolingConnection, // - reaper, // + removeQueryParamOnRedirect,// + strict302Handling, // applicationThreadPool, // proxyServerSelector, // - sslContext, // - sslEngineFactory, // - providerConfig, // - realm, // + useRelativeURIsWithSSLProxies, // + compressionEnabled, // + userAgent,// + realm,// requestFilters, // - responseFilters, // - ioExceptionFilters, // + responseFilters,// + ioExceptionFilters,// maxRequestRetry, // - allowSslConnectionPool, // disableUrlEncodingForBoundRequests, // - removeQueryParamOnRedirect, // - hostnameVerifier, // ioThreadMultiplier, // - strict302Handling, // - useRelativeURIsWithSSLProxies, // + timeConverter,// + providerConfig, // spdyEnabled, // spdyInitialWindowSize, // - spdyMaxConcurrentStreams, // - timeConverter, // - acceptAnyCertificate); + spdyMaxConcurrentStreams); } } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 254d00403d..e276b9f10a 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -45,36 +45,38 @@ 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(); disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); - spdyEnabled = defaultSpdyEnabled(); - spdyInitialWindowSize = defaultSpdyInitialWindowSize(); - spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); acceptAnyCertificate = defaultAcceptAnyCertificate(); + if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } else if (defaultUseProxyProperties()) { proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); } + // AHC 2 + spdyEnabled = defaultSpdyEnabled(); + spdyInitialWindowSize = defaultSpdyInitialWindowSize(); + spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); } void configureExecutors() { @@ -87,38 +89,38 @@ public Thread newThread(Runnable r) { }); } - public AsyncHttpClientConfigBean setMaxTotalConnections(int maxTotalConnections) { - this.maxTotalConnections = maxTotalConnections; + public AsyncHttpClientConfigBean setMaxTotalConnections(int maxConnections) { + this.maxConnections = maxConnections; return this; } - public AsyncHttpClientConfigBean setMaxConnectionPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + public AsyncHttpClientConfigBean setMaxConnectionsPerHost(int maxConnectionsPerHost) { + this.maxConnectionsPerHost = maxConnectionsPerHost; return this; } - public AsyncHttpClientConfigBean setConnectionTimeOutInMs(int connectionTimeOutInMs) { - this.connectionTimeOutInMs = connectionTimeOutInMs; + public AsyncHttpClientConfigBean setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; return this; } - public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + public AsyncHttpClientConfigBean setConnectionTTL(int connectionTTL) { + this.connectionTTL = connectionTTL; return this; } - public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; + public AsyncHttpClientConfigBean setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout; return this; } - public AsyncHttpClientConfigBean setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; + public AsyncHttpClientConfigBean setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; return this; } - public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; + public AsyncHttpClientConfigBean setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; return this; } @@ -147,8 +149,8 @@ public AsyncHttpClientConfigBean setUserAgent(String userAgent) { return this; } - public AsyncHttpClientConfigBean setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; + public AsyncHttpClientConfigBean setAllowPoolingConnections(boolean allowPoolingConnections) { + this.allowPoolingConnections = allowPoolingConnections; return this; } @@ -205,8 +207,8 @@ public AsyncHttpClientConfigBean setMaxRequestRetry(int maxRequestRetry) { return this; } - public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + public AsyncHttpClientConfigBean setAllowPoolingSslConnections(boolean allowPoolingSslConnections) { + this.allowPoolingSslConnections = allowPoolingSslConnections; return this; } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 47af64f89b..e64f1a54b5 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/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 defaultDisableUrlEncodingForBoundRequests() { diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index ad739b546a..25b9be4075 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -31,7 +31,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 AsyncHttpClientConfig}, @@ -42,9 +41,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();
  * 

@@ -500,28 +499,28 @@ public Builder setFollowRedirect(boolean followRedirect) { return this; } - public Builder setMaxConnectionsTotal(int defaultMaxTotalConnections) { - configBuilder.setMaxConnectionsTotal(defaultMaxTotalConnections); + public Builder setMaxConnections(int defaultMaxConnections) { + configBuilder.setMaxConnections(defaultMaxConnections); return this; } - public Builder setMaxConnectionsPerHost(int defaultMaxConnectionPerHost) { - configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionPerHost); + public Builder setMaxConnectionsPerHost(int defaultMaxConnectionsPerHost) { + configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionsPerHost); 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; } @@ -540,13 +539,8 @@ public Builder setUserAgent(String userAgent) { return this; } - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - configBuilder.setAllowPoolingConnection(allowPoolingConnection); - return this; - } - - public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - configBuilder.setScheduledExecutorService(reaper); + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + configBuilder.setAllowPoolingConnections(allowPoolingConnections); return this; } @@ -555,11 +549,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; diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index 49ed3a4f45..d0066c2adf 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -138,11 +138,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.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeout(); } public static boolean followRedirect(AsyncHttpClientConfig config, Request request) { diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index d8f8936d33..301074edc6 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -357,7 +357,7 @@ public Response onCompleted(Response response) throws Exception { // TODO: fix test @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Exception { - 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(); @@ -1226,7 +1226,7 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetDelayHandlerTest() throws Exception { - 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"); @@ -1486,7 +1486,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/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java index cb532d74a9..13d54d417e 100644 --- a/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AuthTimeoutTest.java @@ -211,7 +211,7 @@ protected void inspectException(Throwable t) { } private AsyncHttpClient newClient() { - return getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + return getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); } protected Future execute(AsyncHttpClient client, Server server, boolean preemptive) throws IOException { diff --git a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java index 2c0c3c553c..958361c6b2 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicAuthTest.java @@ -350,7 +350,7 @@ public void basicAuthAsyncConfigTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void basicAuthFileNoKeepAliveTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(false).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(false).build()); try { Future f = client.preparePost(getTargetUrl())// diff --git a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java index 513786fc91..9f13a7b51b 100644 --- a/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BasicHttpsTest.java @@ -81,7 +81,7 @@ public void multipleSSLRequestsTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); + AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowPoolingSslConnections(false).build()); try { String body = "hello there"; c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); @@ -139,7 +139,7 @@ public void failInstantlyIfHostNamesDiffer() throws Exception { public boolean verify(String arg0, SSLSession arg1) { return false; } - }).setRequestTimeoutInMs(20000); + }).setRequestTimeout(20000); client = getAsyncHttpClient(builder.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java index 4dbc04bfb9..727e0d67a0 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyChunkTest.java @@ -35,9 +35,9 @@ public abstract class BodyChunkTest extends AbstractBasicTest { public void negativeContentTypeTest() throws Exception { AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); - confbuilder = confbuilder.setConnectionTimeoutInMs(100); - confbuilder = confbuilder.setMaxConnectionsTotal(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/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java index 2b7c26ee16..baf91d11e2 100644 --- a/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/BodyDeferringAsyncHandlerTest.java @@ -109,7 +109,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/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java index 8d8845faa7..0566ecdbaa 100644 --- a/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ChunkingTest.java @@ -45,11 +45,11 @@ abstract public class ChunkingTest extends AbstractBasicTest { public void testCustomChunking() throws Exception { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); - bc.setAllowPoolingConnection(true); + bc.setAllowPoolingConnections(true); bc.setMaxConnectionsPerHost(1); - bc.setMaxConnectionsTotal(1); - bc.setConnectionTimeoutInMs(1000); - bc.setRequestTimeoutInMs(1000); + bc.setMaxConnections(1); + bc.setConnectionTimeout(1000); + bc.setRequestTimeout(1000); bc.setFollowRedirect(true); AsyncHttpClient c = getAsyncHttpClient(bc.build()); diff --git a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java index be3dc83020..86ea33b6dc 100644 --- a/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ConnectionPoolTest.java @@ -42,7 +42,7 @@ public abstract class ConnectionPoolTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnections() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -64,7 +64,7 @@ public void testMaxTotalConnections() { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -132,7 +132,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -160,7 +160,7 @@ public void multipleMaxConnectionOpenTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaxConnectionsTotal(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/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java index 470eeaaf8e..9783fc4fcf 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java @@ -62,7 +62,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutImageFile() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100 * 6000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100 * 6000).build()); try { Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); assertEquals(response.getStatusCode(), 200); diff --git a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java index 929ec24856..cefa7083aa 100644 --- a/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/IdleStateHandlerTest.java @@ -61,7 +61,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void idleStateTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(10 * 1000).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(10 * 1000).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { diff --git a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java index 31b6ddc359..4f626fd3f9 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxConnectionsInThreads.java @@ -51,8 +51,8 @@ public void testMaxConnectionsWithinThreads() { String[] urls = new String[] { servletEndpointUri.toString(), servletEndpointUri.toString() }; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(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/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java index 245abb9de9..d12b98c613 100644 --- a/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MaxTotalConnectionTest.java @@ -39,7 +39,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().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { boolean caughtError = false; for (int i = 0; i < urls.length; i++) { @@ -61,7 +61,7 @@ public void testMaxTotalConnectionsExceedingException() { public void testMaxTotalConnections() { String[] urls = new String[] { "http://google.com/", "http://lenta.ru/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(2).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1).build()); try { for (String url : urls) { try { @@ -82,7 +82,7 @@ public void testMaxTotalConnections() { public void testMaxTotalConnectionsCorrectExceptionHandling() { String[] urls = new String[] { "http://google.com/", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaxConnectionsTotal(1).setMaxConnectionsPerHost(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { List> futures = new ArrayList>(); boolean caughtError = false; diff --git a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java index 0e27a0fb86..8ce64afc51 100644 --- a/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java +++ b/api/src/test/java/org/asynchttpclient/async/NoNullResponseTest.java @@ -56,8 +56,8 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Exception { } 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).setMaxConnectionsPerHost(-1).setMaxConnectionsTotal(-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/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java index f6cc5764ec..9063a8f87e 100644 --- a/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PerRequestTimeoutTest.java @@ -115,7 +115,7 @@ 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(); Response response = responseFuture.get(); @@ -132,7 +132,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); @@ -153,7 +153,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/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java index 0d37f66e5c..51400e3040 100644 --- a/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/PutLargeFileTest.java @@ -41,7 +41,7 @@ public void testPutLargeFile() throws Exception { int timeout = (int) file.length() / 1000; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(timeout).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build()); try { Response response = client.preparePut(getTargetUrl()).setBody(file).execute().get(); assertEquals(response.getStatusCode(), 200); diff --git a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java index a52ccd4157..e3a1993058 100644 --- a/api/src/test/java/org/asynchttpclient/async/RC10KTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RC10KTest.java @@ -99,7 +99,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 ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); + AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnections(true).build()); try { List> resps = new ArrayList>(C10K); int i = 0; diff --git a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java index 8241e49f4d..26bfbfc2f9 100644 --- a/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RedirectConnectionUsageTest.java @@ -74,11 +74,11 @@ public void setUp() throws Exception { public void testGetRedirectFinalUrl() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// + .setAllowPoolingConnections(true)// .setMaxConnectionsPerHost(1)// - .setMaxConnectionsTotal(1)// - .setConnectionTimeoutInMs(1000)// - .setRequestTimeoutInMs(1000)// + .setMaxConnections(1)// + .setConnectionTimeout(1000)// + .setRequestTimeout(1000)// .setFollowRedirect(true)// .build(); diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index 36a735b610..f5b46b21fb 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -53,7 +53,7 @@ public abstract class RemoteSiteTest extends AbstractBasicTest { @Test(groups = { "online", "default_provider" }) public void testGoogleCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -64,7 +64,7 @@ public void testGoogleCom() throws Exception { @Test(groups = { "online", "default_provider" }) public void testMailGoogleCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -77,7 +77,7 @@ public void testMailGoogleCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -90,7 +90,7 @@ public void testMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testWwwMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -103,7 +103,7 @@ public void testWwwMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) // FIXME public void testUpdateMicrosoftCom() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -115,7 +115,7 @@ public void testUpdateMicrosoftCom() throws Exception { @Test(groups = { "online", "default_provider" }) public void testGoogleComWithTimeout() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -154,8 +154,8 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Exception { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirect(true) - .setAllowPoolingConnection(false).setMaxRedirects(6).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).setFollowRedirect(true) + .setAllowPoolingConnections(false).setMaxRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index c4aa459a2b..a7f4615795 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -49,8 +49,8 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void inpuStreamBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(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()))); @@ -65,8 +65,8 @@ public void inpuStreamBodyConsumerTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(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)); @@ -82,8 +82,8 @@ public void stringBuilderBodyConsumerTest() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void byteArrayOutputStreamBodyConsumerTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(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)); @@ -117,8 +117,8 @@ public void requestByteArrayOutputStreamBodyConsumerTest() throws Exception { */ @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100) - .setMaxConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100) + .setMaxConnections(50).setRequestTimeout(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") .build(); try { File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); diff --git a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java index 3b1763e768..90ffb19938 100644 --- a/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/TransferListenerTest.java @@ -147,7 +147,7 @@ public void basicPutFileTest() throws Exception { File file = createTempFile(1024 * 100 * 10); int timeout = (int) (file.length() / 1000); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(timeout).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build()); try { TransferCompletionHandler tl = new TransferCompletionHandler(); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java index b83618df63..f887b9624e 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/ConnectionManager.java @@ -75,11 +75,11 @@ public class ConnectionManager { this.connectionPool = connectionPool; canDestroyPool = false; } else { - this.connectionPool = new ConnectionPool(config.getMaxConnectionPerHost(),// - config.getMaxTotalConnections(),// + this.connectionPool = new ConnectionPool(config.getMaxConnectionsPerHost(),// + config.getMaxConnections(),// null,// - config.getConnectionTimeoutInMs(),// - config.getIdleConnectionInPoolTimeoutInMs(),// + config.getConnectionTimeout(),// + config.getPooledConnectionIdleTimeout(),// 2000); canDestroyPool = true; } @@ -211,7 +211,7 @@ private static int getPort(final UriComponents uri, final int p) { private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws ExecutionException, InterruptedException, TimeoutException, IOException { - final int cTimeout = provider.getClientConfig().getConnectionTimeoutInMs(); + final int cTimeout = provider.getClientConfig().getConnectionTimeout(); final FutureImpl future = Futures.createSafeFuture(); final CompletionHandler ch = Futures.toCompletionHandler(future, createConnectionCompletionHandler(request, requestFuture, null)); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index dd8d457fd6..620606a399 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -277,7 +277,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { ws.onConnect(); WebSocketHolder.set(ctx.getConnection(), context.getProtocolHandler(), ws); ((WebSocketUpgradeHandler) context.getHandler()).onSuccess(context.getWebSocket()); - final int wsTimeout = context.getProvider().getClientConfig().getWebSocketIdleTimeoutInMs(); + final int wsTimeout = context.getProvider().getClientConfig().getWebSocketReadTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER : wsTimeout), TimeUnit.MILLISECONDS); context.result(handler.onCompleted()); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index fa6a759e53..3bc8ed5f80 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -214,7 +214,7 @@ void initializeTransport(final AsyncHttpClientConfig clientConfig) { final FilterChainBuilder secure = FilterChainBuilder.stateless(); secure.add(new TransportFilter()); - final int timeout = clientConfig.getRequestTimeoutInMs(); + final int timeout = clientConfig.getRequestTimeout(); if (timeout > 0) { int delay = 500; //noinspection ConstantConditions @@ -232,7 +232,7 @@ public long getTimeout(FilterChainContext ctx) { final HttpTxContext context = HttpTxContext.get(ctx); if (context != null) { if (context.isWSRequest()) { - return clientConfig.getWebSocketIdleTimeoutInMs(); + return clientConfig.getWebSocketReadTimeout(); } int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); if (requestTimeout > 0) { diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java index acf6c92a3a..be0aed7b7f 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyConnectionPoolTest.java @@ -40,8 +40,8 @@ public void testMaxTotalConnectionsException() { @Override @Test public void multipleMaxConnectionOpenTest() throws Exception { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000) - .setMaxConnectionsTotal(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/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 1aac4fcfce..2beca1a78f 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -135,7 +135,7 @@ private void doSimpleFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) - .setMaxConnectionsTotal(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = @@ -238,7 +238,7 @@ private void doNonBlockingFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) - .setMaxConnectionsTotal(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java index ea02d5fc57..116a186459 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/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) .setDisableUrlEncodingForBoundRequests(true) .setIOThreadMultiplier(2) // 2 is default .build(); diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java index 743255d00b..3829983aae 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -82,7 +82,7 @@ public void unexpectingTimeoutTest() 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() { @Override diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 637a619c6f..dd36702b85 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -31,7 +31,7 @@ public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); private final ChannelPool channelPool; - private final boolean maxTotalConnectionsEnabled; + private final boolean maxConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; private final int maxConnectionsPerHost; @@ -42,9 +42,9 @@ public class ChannelManager { public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { this.channelPool = channelPool; - maxTotalConnectionsEnabled = config.getMaxTotalConnections() > 0; + maxConnectionsEnabled = config.getMaxConnections() > 0; - if (maxTotalConnectionsEnabled) { + if (maxConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override public boolean remove(Object o) { @@ -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(); @@ -103,7 +103,7 @@ public boolean removeAll(Channel connection) { } private boolean tryAcquireGlobal() { - return !maxTotalConnectionsEnabled || freeChannels.tryAcquire(); + return !maxConnectionsEnabled || freeChannels.tryAcquire(); } private Semaphore getFreeConnectionsForHost(String poolKey) { @@ -156,7 +156,7 @@ public void closeChannel(Channel channel) { } public void abortChannelPreemption(String poolKey) { - if (maxTotalConnectionsEnabled) + if (maxConnectionsEnabled) freeChannels.release(); if (maxConnectionsPerHostEnabled) getFreeConnectionsForHost(poolKey).release(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index 54376e29b1..304d2d7931 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -126,7 +126,7 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig ChannelPool cp = nettyProviderConfig.getChannelPool(); if (cp == null) { - if (config.isAllowPoolingConnection()) { + if (config.isAllowPoolingConnections()) { cp = new DefaultChannelPool(config, nettyTimer); } else { cp = new NoopChannelPool(); @@ -143,7 +143,7 @@ public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig secureWebSocketBootstrap.option(key, value); } - int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; + int timeOut = config.getConnectionTimeout() > 0 ? config.getConnectionTimeout() : Integer.MAX_VALUE; plainBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); webSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); secureBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); @@ -340,7 +340,7 @@ 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.getMaxTotalConnections())); + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); try { asyncHandler.onThrowable(ex); } catch (Exception e) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index f46a63d310..88e9b72556 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index ff18a9d5b8..5997c6b77d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -230,7 +230,7 @@ private ListenableFuture sendRequestWithNewChannel(// // only compute when maxConnectionPerHost is enabled // FIXME clean up - if (config.getMaxConnectionPerHost() > 0) + if (config.getMaxConnectionsPerHost() > 0) poolKey = channels.getPoolKey(future); channelPreempted = channels.preemptChannel(asyncHandler, poolKey); @@ -390,11 +390,11 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { timeoutsHolder.requestTimeout = requestTimeout; } - int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); - if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs < requestTimeoutInMs) { + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs Timeout idleConnectionTimeout = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, - timeoutsHolder, closed, requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); + timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java index ef02fa7896..6c333eae1b 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyRequestThrottleTimeoutTest.java @@ -82,7 +82,7 @@ public void testRequestTimeout() throws IOException { final Semaphore requestThrottle = new Semaphore(1); final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true) - .setAllowPoolingConnection(true).setMaxConnectionsTotal(1).build()); + .setAllowPoolingConnections(true).setMaxConnections(1).build()); int samples = 10; diff --git a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java index 7c29f993e3..c5d1798595 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/RetryNonBlockingIssue.java @@ -88,10 +88,10 @@ private ListenableFuture testMethodRequest(AsyncHttpClient client, int public void testRetryNonBlocking() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaxConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000)// + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000)// .build(); AsyncHttpClient client = getAsyncHttpClient(config); @@ -124,10 +124,10 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, Exe public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaxConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000)// + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000)// .build(); AsyncHttpClient client = getAsyncHttpClient(config); From 800cd02544d6ca0ab926f9af1c8c7ada41397ab1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:16:10 +0200 Subject: [PATCH 0153/2070] Rename webSocketReadTimeout into webSocketTimeout --- .../AsyncHttpClientConfig.java | 20 +++++++++---------- .../AsyncHttpClientConfigBean.java | 2 +- .../AsyncHttpClientConfigDefaults.java | 4 ++-- .../providers/grizzly/EventHandler.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 265008c2bb..5146b997a6 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -73,7 +73,7 @@ public class AsyncHttpClientConfig { protected int requestTimeout; protected int readTimeout; - protected int webSocketReadTimeout; + protected int webSocketTimeout; protected boolean allowPoolingConnections; protected boolean allowPoolingSslConnections; @@ -118,7 +118,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// int maxConnectionsPerHost,// int requestTimeout,// int readTimeout,// - int webSocketIdleTimeout,// + int webSocketTimeout,// boolean allowPoolingConnection,// boolean allowSslConnectionPool,// int idleConnectionInPoolTimeout,// @@ -153,7 +153,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.maxConnectionsPerHost = maxConnectionsPerHost; this.requestTimeout = requestTimeout; this.readTimeout = readTimeout; - this.webSocketReadTimeout = webSocketIdleTimeout; + this.webSocketTimeout = webSocketTimeout; this.allowPoolingConnections = allowPoolingConnection; this.allowPoolingSslConnections = allowSslConnectionPool; this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; @@ -216,8 +216,8 @@ public int getConnectionTimeout() { * Return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link org.asynchttpclient.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketReadTimeout() { - return webSocketReadTimeout; + public int getWebSocketTimeout() { + return webSocketTimeout; } /** @@ -532,7 +532,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(); @@ -605,12 +605,12 @@ public Builder setConnectionTimeout(int connectionTimeout) { /** * Set the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeout + * @param webSocketTimeout * the maximum time in millisecond an {@link org.asynchttpclient.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketReadTimeout(int webSocketReadTimeout) { - this.webSocketReadTimeout = webSocketReadTimeout; + public Builder setWebSocketTimeout(int webSocketTimeout) { + this.webSocketTimeout = webSocketTimeout; return this; } @@ -1099,7 +1099,7 @@ public AsyncHttpClientConfig build() { maxConnectionsPerHost,// requestTimeout,// readTimeout,// - webSocketReadTimeout,// + webSocketTimeout,// allowPoolingConnections,// allowPoolingSslConnections,// pooledConnectionIdleTimeout,// diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index e276b9f10a..d68c6a8984 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index e64f1a54b5..8ecd353491 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/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/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 620606a399..6a99e9335a 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -277,7 +277,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { ws.onConnect(); WebSocketHolder.set(ctx.getConnection(), context.getProtocolHandler(), ws); ((WebSocketUpgradeHandler) context.getHandler()).onSuccess(context.getWebSocket()); - final int wsTimeout = context.getProvider().getClientConfig().getWebSocketReadTimeout(); + final int wsTimeout = context.getProvider().getClientConfig().getWebSocketTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER : wsTimeout), TimeUnit.MILLISECONDS); context.result(handler.onCompleted()); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 3bc8ed5f80..9215900d30 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -232,7 +232,7 @@ public long getTimeout(FilterChainContext ctx) { final HttpTxContext context = HttpTxContext.get(ctx); if (context != null) { if (context.isWSRequest()) { - return clientConfig.getWebSocketReadTimeout(); + return clientConfig.getWebSocketTimeout(); } int requestTimeout = AsyncHttpProviderUtils.requestTimeout(clientConfig, context.getRequest()); if (requestTimeout > 0) { From 6e340549e2591e52684d450199cdceaceedd71ba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:25:52 +0200 Subject: [PATCH 0154/2070] Rename IdleConnectionTimeout into ReadTimeout --- .../netty/request/NettyRequestSender.java | 6 ++--- ...merTask.java => ReadTimeoutTimerTask.java} | 24 +++++++++---------- .../netty/request/timeout/TimeoutsHolder.java | 8 +++---- 3 files changed, 19 insertions(+), 19 deletions(-) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/{IdleConnectionTimeoutTimerTask.java => ReadTimeoutTimerTask.java} (71%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 5997c6b77d..79b76edb3d 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -33,7 +33,7 @@ import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.timeout.IdleConnectionTimeoutTimerTask; +import org.asynchttpclient.providers.netty.request.timeout.ReadTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; import org.asynchttpclient.uri.UriComponents; @@ -393,9 +393,9 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { int readTimeout = config.getReadTimeout(); if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = channels.newTimeoutInMs(new IdleConnectionTimeoutTimerTask(nettyResponseFuture, channels, + Timeout idleConnectionTimeout = channels.newTimeoutInMs(new ReadTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); - timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; + timeoutsHolder.readTimeout = idleConnectionTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); } catch (RejectedExecutionException ex) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java similarity index 71% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java index bea473c9d8..6199c9cd9b 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/IdleConnectionTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -24,20 +24,20 @@ import java.util.concurrent.atomic.AtomicBoolean; -public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { +public class ReadTimeoutTimerTask extends TimeoutTimerTask { - private final long idleConnectionTimeout; + private final long readTimeout; private final long requestTimeoutInstant; - public IdleConnectionTimeoutTimerTask(// + public ReadTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// Channels channels,// TimeoutsHolder timeoutsHolder,// AtomicBoolean clientClosed,// long requestTimeout,// - long idleConnectionTimeout) { + long readTimeout) { super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); - this.idleConnectionTimeout = idleConnectionTimeout; + this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } @@ -52,23 +52,23 @@ 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 = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); nettyResponseFuture.setIdleConnectionTimeoutReached(); - } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { + } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.idleConnectionTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); + timeoutsHolder.readTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.idleConnectionTimeout = null; + timeoutsHolder.readTimeout = null; } } else { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java index a27e903510..d032672a4a 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java @@ -23,7 +23,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)) { @@ -31,9 +31,9 @@ public void cancel() { requestTimeout.cancel(); requestTimeout = null; } - if (idleConnectionTimeout != null) { - idleConnectionTimeout.cancel(); - idleConnectionTimeout = null; + if (readTimeout != null) { + readTimeout.cancel(); + readTimeout = null; } } } From 1fb3b426ef513a76b4d4a64f09d999b597dd136c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Jul 2014 16:42:01 +0200 Subject: [PATCH 0155/2070] Unused parameter --- .../providers/netty/channel/pool/DefaultChannelPool.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index 88e9b72556..3a04157660 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/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,// + public DefaultChannelPool( long maxIdleTime,// int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// From d091dfb6cc011cd77b0ee23cb7d09a93170b9bc6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:05:57 +0200 Subject: [PATCH 0156/2070] Minor clean up --- .../netty/future/StackTraceInspector.java | 38 +++++++++---------- .../netty/request/NettyConnectListener.java | 13 +++---- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index 94abc067b2..80d99fa1be 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -14,57 +14,57 @@ public class StackTraceInspector { - private static boolean exceptionInMethod(Throwable cause, String className, String methodName) { + private static boolean exceptionInMethod(Throwable t, String className, String methodName) { try { - for (StackTraceElement element : cause.getStackTrace()) { + for (StackTraceElement element : t.getStackTrace()) { if (element.getClassName().equals(className) && element.getMethodName().equals(methodName)) return true; } - } catch (Throwable t) { + } catch (Throwable ignore) { } return false; } - private static boolean abortOnConnectCloseException(Throwable cause) { + private static boolean abortOnConnectCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketChannelImpl", "checkConnect")) + if (exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect")) return true; - if (cause.getCause() != null) - return abortOnConnectCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnConnectCloseException(t.getCause()); return false; } - public static boolean abortOnDisconnectException(Throwable cause) { + public static boolean abortOnDisconnectException(Throwable t) { - if (exceptionInMethod(cause, "io.netty.handler.ssl.SslHandler", "disconnect")) + if (exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect")) return true; - if (cause.getCause() != null) - return abortOnConnectCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnConnectCloseException(t.getCause()); return false; } - public static boolean abortOnReadCloseException(Throwable cause) { + public static boolean abortOnReadCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketDispatcher", "read")) + if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "read")) return true; - if (cause.getCause() != null) - return abortOnReadCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnReadCloseException(t.getCause()); return false; } - public static boolean abortOnWriteCloseException(Throwable cause) { + public static boolean abortOnWriteCloseException(Throwable t) { - if (exceptionInMethod(cause, "sun.nio.ch.SocketDispatcher", "write")) + if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "write")) return true; - if (cause.getCause() != null) - return abortOnWriteCloseException(cause.getCause()); + if (t.getCause() != null) + return abortOnWriteCloseException(t.getCause()); return false; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 05b36fd230..c1ca441e1f 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -124,7 +124,7 @@ public void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", channel, canRetry); if (canRetry// && cause != null// - && (StackTraceInspector.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { + && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { LOGGER.debug("Retrying {} ", future.getNettyRequest()); if (requestSender.retry(future, channel)) { @@ -135,19 +135,18 @@ public void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, channel); boolean printCause = cause != null && cause.getMessage() != null; - String printedCause = printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString(); + String url = future.getURI().toUrl(); + String printedCause = printCause ? cause.getMessage() + " to " + url : url; ConnectException e = new ConnectException(printedCause); - if (cause != null) { + if (cause != null) e.initCause(cause); - } future.abort(e); } public final void operationComplete(ChannelFuture f) throws Exception { - if (f.isSuccess()) { + if (f.isSuccess()) onFutureSuccess(f.channel()); - } else { + else onFutureFailure(f.channel(), f.cause()); - } } } From e507109646ce70df7e6b095e5dab5ad563f42b8f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:28:19 +0200 Subject: [PATCH 0157/2070] Optimize stack scan, close #635 --- .../netty/future/StackTraceInspector.java | 26 ++++++++----------- .../providers/netty/handler/Processor.java | 2 +- .../netty/request/ProgressListener.java | 3 +-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index 80d99fa1be..d47878b419 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -47,24 +47,20 @@ public static boolean abortOnDisconnectException(Throwable t) { return false; } - public static boolean abortOnReadCloseException(Throwable t) { + public static boolean abortOnReadOrWriteException(Throwable t) { - if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "read")) - return true; - - if (t.getCause() != null) - return abortOnReadCloseException(t.getCause()); - - return false; - } - - public static boolean abortOnWriteCloseException(Throwable t) { - - if (exceptionInMethod(t, "sun.nio.ch.SocketDispatcher", "write")) - return true; + 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 abortOnWriteCloseException(t.getCause()); + return abortOnReadOrWriteException(t.getCause()); return false; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 7c69daeba7..f1d6a1d3e0 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -183,7 +183,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep } } - if (StackTraceInspector.abortOnReadCloseException(cause) || StackTraceInspector.abortOnWriteCloseException(cause)) { + if (StackTraceInspector.abortOnReadOrWriteException(cause)) { LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java index ad31a075bc..78c9f35919 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java @@ -61,8 +61,7 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { } catch (RuntimeException ex) { LOGGER.debug(ex.getMessage(), ex); } - } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadCloseException(cause) - || StackTraceInspector.abortOnWriteCloseException(cause)) { + } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { if (LOGGER.isDebugEnabled()) LOGGER.debug(cause.getMessage(), cause); From e1c7f4aeef9e07c98d33f8d1121dbd77559efb6b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:32:18 +0200 Subject: [PATCH 0158/2070] minor clean up --- .../netty/future/StackTraceInspector.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java index d47878b419..f4a6589768 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java @@ -26,25 +26,13 @@ private static boolean exceptionInMethod(Throwable t, String className, String m } private static boolean abortOnConnectCloseException(Throwable t) { - - if (exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect")) - return true; - - if (t.getCause() != null) - return abortOnConnectCloseException(t.getCause()); - - return false; + return exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); } public static boolean abortOnDisconnectException(Throwable t) { - - if (exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect")) - return true; - - if (t.getCause() != null) - return abortOnConnectCloseException(t.getCause()); - - return false; + return exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); } public static boolean abortOnReadOrWriteException(Throwable t) { From c3589e01b878030dddad8ebefb8ed5eef8a375fc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 14:32:55 +0200 Subject: [PATCH 0159/2070] NettyResponseFuture.get should always block on the latch, close #489 --- .../providers/netty/future/NettyResponseFuture.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 1418c3c4a5..9d2a692f77 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -156,14 +156,13 @@ public boolean cancel(boolean force) { @Override public V get() throws InterruptedException, ExecutionException { - if (!isDone()) - latch.await(); + latch.await(); return getContent(); } @Override 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 4ae7bc92e8a7b0e6b45e535ac2488bd1e8b929ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 15:01:30 +0200 Subject: [PATCH 0160/2070] minor clean up --- .../util/AuthenticatorUtils.java | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java index 594eafa1a3..0da1666af1 100644 --- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java @@ -50,38 +50,30 @@ private static String computeRealmURI(Realm realm) { public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException { 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(StandardCharsets.ISO_8859_1)); } - public static String computeDigestAuthentication(ProxyServer proxy) { - try { - StringBuilder builder = new StringBuilder().append("Digest "); - construct(builder, "username", proxy.getPrincipal(), true); - return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - 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 399d78c9dd79d30d3e5e63363d1e27ad1bd2cd84 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 11:58:28 -0700 Subject: [PATCH 0161/2070] [master] + fix issue #637 https://github.com/AsyncHttpClient/async-http-client/issues/637 "AHC with Grizzly provider not handling SSL Connect/tunnelling with Proxy" --- .../providers/grizzly/EventHandler.java | 15 +++++++++++++++ .../filters/AsyncHttpClientEventFilter.java | 8 ++++++++ .../providers/grizzly/filters/ProxyFilter.java | 2 +- .../providers/grizzly/filters/TunnelFilter.java | 4 ++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 6a99e9335a..2de816a312 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -55,6 +55,8 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.http.HttpRequestPacket; public final class EventHandler { @@ -304,6 +306,19 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { } + public boolean onHttpHeaderParsed(final HttpHeader httpHeader, + final Buffer buffer, final FilterChainContext 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("rawtypes") public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java index 6afb87197a..687984e6a8 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientEventFilter.java @@ -22,6 +22,7 @@ import java.io.IOException; import org.asynchttpclient.providers.grizzly.filters.events.GracefulCloseEvent; +import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.filterchain.FilterChainEvent; import org.glassfish.grizzly.filterchain.NextAction; import org.glassfish.grizzly.http.HttpResponsePacket; @@ -111,6 +112,13 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx eventHandler.onHttpHeadersParsed(httpHeader, ctx); } + @Override + protected boolean onHttpHeaderParsed(final HttpHeader httpHeader, + final Buffer buffer, final FilterChainContext ctx) { + super.onHttpHeaderParsed(httpHeader, buffer, ctx); + return eventHandler.onHttpHeaderParsed(httpHeader, buffer, ctx); + } + @Override protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { return eventHandler.onHttpPacketParsed(httpHeader, ctx); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java index ded8031daf..4b30c7c6cf 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java @@ -100,7 +100,7 @@ private String generateAuthHeader(final Realm realm) { case BASIC: return computeBasicAuthentication(realm); case DIGEST: - return computeDigestAuthentication(proxyServer); + return computeDigestAuthentication(realm); case NTLM: return NTLM_ENGINE.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); default: diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java index ed9723fa96..aae301883f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/TunnelFilter.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. @@ -94,7 +94,7 @@ public NextAction handleEvent(FilterChainContext ctx, FilterChainEvent event) th suspendedContext.resume(ctx.getInvokeAction()); // Stop further event processing. - ctx.getStopAction(); + return ctx.getStopAction(); } return ctx.getInvokeAction(); } From 34a95f04c22198b6575c9fd82f0f2ef117e1cbed Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 21:37:16 -0700 Subject: [PATCH 0162/2070] [master] + fix issue #631 https://github.com/AsyncHttpClient/async-http-client/issues/631 "Grizzly provider aggressively set cookie missing domain and path to /" --- .../providers/grizzly/EventHandler.java | 6 +++--- .../grizzly/filters/AsyncHttpClientFilter.java | 12 ++++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java index 2de816a312..50675690ac 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/EventHandler.java @@ -185,7 +185,7 @@ public void onInitialLineParsed(HttpHeader httpHeader, FilterChainContext ctx) { try { context.result(handler.onCompleted()); context.done(); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } @@ -289,7 +289,7 @@ public void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { "WebSocket protocol error: unexpected HTTP response status during handshake."); context.result(null); } - } catch (Exception e) { + } catch (Throwable e) { httpHeader.setSkipRemainder(true); context.abort(e); } @@ -341,7 +341,7 @@ public boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) if (handler != null) { try { context.result(handler.onCompleted()); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } else { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 21dc88c516..7d7f002699 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -520,17 +520,13 @@ private void addCookies(final Request request, final HttpRequestPacket requestPa } } - private static void convertCookies(final Collection cookies, final org.glassfish.grizzly.http.Cookie[] gCookies) { + private static void convertCookies(final Collection cookies, + final org.glassfish.grizzly.http.Cookie[] gCookies) { int idx = 0; if (!cookies.isEmpty()) { 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.setMaxAge(cookie.getMaxAge()); - gCookie.setSecure(cookie.isSecure()); - gCookies[idx] = gCookie; - idx++; + gCookies[idx++] = new org.glassfish.grizzly.http.Cookie( + cookie.getName(), cookie.getValue()); } } } From dd92f36a0ff9cfa56d5b93aec9a24e7adfcfd1c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 18:26:23 +0200 Subject: [PATCH 0163/2070] Make AHC 1.9 and AHC2 code converge, close #638 --- .../providers/netty/DiscardEvent.java | 0 .../netty/NettyAsyncHttpProvider.java | 56 +- .../netty/NettyAsyncHttpProviderConfig.java | 51 +- .../netty/channel/ChannelManager.java | 298 ++++++++- .../providers/netty/channel/Channels.java | 406 +------------ .../CleanupChannelGroup.java | 2 +- .../netty/channel/SslInitializer.java | 10 +- .../netty/channel/pool/ChannelPool.java | 21 +- .../channel/pool/DefaultChannelPool.java | 0 .../netty/channel/pool/NoopChannelPool.java | 20 +- .../netty/future/NettyResponseFuture.java | 54 +- .../netty/future/StackTraceInspector.java | 0 .../providers/netty/handler/HttpProtocol.java | 318 +++++----- .../providers/netty/handler/Processor.java | 127 ++-- .../providers/netty/handler/Protocol.java | 102 ++-- .../netty/handler/WebSocketProtocol.java | 109 ++-- .../netty/request/NettyConnectListener.java | 38 +- .../providers/netty/request/NettyRequest.java | 22 +- .../netty/request/NettyRequestFactory.java | 56 +- .../netty/request/NettyRequestSender.java | 572 ++++++++++-------- .../netty/request/ProgressListener.java | 37 +- .../netty/request/body/BodyChunkedInput.java | 5 +- .../netty/request/body/BodyFileRegion.java | 5 +- .../request/body/FeedableBodyGenerator.java | 5 +- .../netty/request/body/NettyBody.java | 20 +- .../netty/request/body/NettyBodyBody.java | 20 +- .../request/body/NettyByteArrayBody.java | 20 +- .../netty/request/body/NettyFileBody.java | 20 +- .../request/body/NettyInputStreamBody.java | 20 +- .../request/body/NettyMultipartBody.java | 29 +- .../request/timeout/ReadTimeoutTimerTask.java | 36 +- .../timeout/RequestTimeoutTimerTask.java | 35 +- .../request/timeout/TimeoutTimerTask.java | 44 +- .../netty/request/timeout/TimeoutsHolder.java | 20 +- .../netty/response/EagerResponseBodyPart.java | 4 +- .../netty/response/LazyResponseBodyPart.java | 0 .../netty/response/NettyResponse.java | 46 +- .../netty/response/NettyResponseBodyPart.java | 20 +- .../netty/response/ResponseHeaders.java | 20 +- .../netty/response/ResponseStatus.java | 23 +- .../{ByteBufUtil.java => ByteBufUtils.java} | 4 +- .../util/{HttpUtil.java => HttpUtils.java} | 4 +- .../providers/netty/ws/NettyWebSocket.java | 5 +- ...WebSocketUtil.java => WebSocketUtils.java} | 7 +- 44 files changed, 1290 insertions(+), 1421 deletions(-) mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/{util => channel}/CleanupChannelGroup.java (98%) mode change 100644 => 100755 mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/{ByteBufUtil.java => ByteBufUtils.java} (96%) mode change 100644 => 100755 rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/{HttpUtil.java => HttpUtils.java} (96%) mode change 100644 => 100755 mode change 100644 => 100755 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/{WebSocketUtil.java => WebSocketUtils.java} (91%) mode change 100644 => 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/DiscardEvent.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java old mode 100644 new mode 100755 index 5fb2104212..9f65646fe5 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProvider.java @@ -1,41 +1,44 @@ /* - * 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 org.asynchttpclient.providers.netty; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpProvider; import org.asynchttpclient.ListenableFuture; import org.asynchttpclient.Request; -import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - public class NettyAsyncHttpProvider implements AsyncHttpProvider { private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); private final NettyAsyncHttpProviderConfig nettyConfig; private final AtomicBoolean closed = new AtomicBoolean(false); - private final Channels channels; + private final ChannelManager channelManager; private final NettyRequestSender requestSender; + private final boolean allowStopNettyTimer; + private final Timer nettyTimer; public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @@ -43,16 +46,29 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig() : new NettyAsyncHttpProviderConfig(); - channels = new Channels(config, nettyConfig); - requestSender = new NettyRequestSender(closed, config, nettyConfig, channels); - channels.configureProcessor(requestSender, closed); + allowStopNettyTimer = nettyConfig.getNettyTimer() == null; + nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyConfig.getNettyTimer(); + + channelManager = new ChannelManager(config, nettyConfig, nettyTimer); + requestSender = new NettyRequestSender(config, nettyConfig, channelManager, nettyTimer, closed); + channelManager.configureBootstraps(requestSender, closed); + } + + private Timer newNettyTimer() { + HashedWheelTimer timer = new HashedWheelTimer(); + timer.start(); + return timer; } @Override public void close() { if (closed.compareAndSet(false, true)) { try { - channels.close(); + channelManager.close(); + + if (allowStopNettyTimer) + nettyTimer.stop(); + } catch (Throwable t) { LOGGER.warn("Unexpected error on close", t); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java old mode 100644 new mode 100755 index 554e1643c1..f066ab51d5 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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 org.asynchttpclient.providers.netty; @@ -127,17 +124,17 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { /** * HttpClientCodec's maxInitialLineLength */ - private int maxInitialLineLength = 4096; + private int httpClientCodecMaxInitialLineLength = 4096; /** * HttpClientCodec's maxHeaderSize */ - private int maxHeaderSize = 8192; + private int httpClientCodecMaxHeaderSize = 8192; /** * HttpClientCodec's maxChunkSize */ - private int maxChunkSize = 8192; + private int httpClientCodecMaxChunkSize = 8192; private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); @@ -191,28 +188,28 @@ public void setWssAdditionalChannelInitializer(AdditionalChannelInitializer wssA this.wssAdditionalChannelInitializer = wssAdditionalChannelInitializer; } - public int getMaxInitialLineLength() { - return maxInitialLineLength; + public int getHttpClientCodecMaxInitialLineLength() { + return httpClientCodecMaxInitialLineLength; } - public void setMaxInitialLineLength(int maxInitialLineLength) { - this.maxInitialLineLength = maxInitialLineLength; + public void setHttpClientCodecMaxInitialLineLength(int httpClientCodecMaxInitialLineLength) { + this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength; } - public int getMaxHeaderSize() { - return maxHeaderSize; + public int getHttpClientCodecMaxHeaderSize() { + return httpClientCodecMaxHeaderSize; } - public void setMaxHeaderSize(int maxHeaderSize) { - this.maxHeaderSize = maxHeaderSize; + public void setHttpClientCodecMaxHeaderSize(int httpClientCodecMaxHeaderSize) { + this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize; } - public int getMaxChunkSize() { - return maxChunkSize; + public int getHttpClientCodecMaxChunkSize() { + return httpClientCodecMaxChunkSize; } - public void setMaxChunkSize(int maxChunkSize) { - this.maxChunkSize = maxChunkSize; + public void setHttpClientCodecMaxChunkSize(int httpClientCodecMaxChunkSize) { + this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize; } public ResponseBodyPartFactory getBodyPartFactory() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java old mode 100644 new mode 100755 index dd36702b85..047dfc2a26 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -13,37 +13,104 @@ */ package org.asynchttpclient.providers.netty.channel; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.util.CleanupChannelGroup; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; import io.netty.channel.group.ChannelGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpContentDecompressor; +import io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; +import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.util.Timer; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.Callback; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; +import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.handler.HttpProtocol; +import org.asynchttpclient.providers.netty.handler.Processor; +import org.asynchttpclient.providers.netty.handler.WebSocketProtocol; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.asynchttpclient.uri.UriComponents; +import org.asynchttpclient.util.SslUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; 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"; + 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; + + private final EventLoopGroup eventLoopGroup; + private final boolean allowReleaseEventLoopGroup; + + private final Bootstrap plainBootstrap; + private final Bootstrap secureBootstrap; + private final Bootstrap webSocketBootstrap; + private final Bootstrap secureWebSocketBootstrap; + + private final long handshakeTimeoutInMillis; private final ChannelPool channelPool; private final boolean maxConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; - private final int maxConnectionsPerHost; private final boolean maxConnectionsPerHostEnabled; private final ConcurrentHashMap freeChannelsPerHost; private final ConcurrentHashMap channel2KeyPool; - public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + private Processor wsProcessor; + + public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, Timer nettyTimer) { + + this.config = config; + this.nettyConfig = nettyConfig; + + ChannelPool channelPool = nettyConfig.getChannelPool(); + if (channelPool == null && config.isAllowPoolingConnections()) { + channelPool = new DefaultChannelPool(config, nettyTimer); + } else if (channelPool == null) { + channelPool = new NoopChannelPool(); + } this.channelPool = channelPool; maxConnectionsEnabled = config.getMaxConnections() > 0; - + maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; + if (maxConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override @@ -69,9 +136,6 @@ public boolean remove(Object o) { freeChannels = null; } - maxConnectionsPerHost = config.getMaxConnectionsPerHost(); - maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; - if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); channel2KeyPool = new ConcurrentHashMap(); @@ -79,6 +143,104 @@ public boolean remove(Object o) { freeChannelsPerHost = null; channel2KeyPool = null; } + + handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + + // check if external EventLoopGroup is defined + allowReleaseEventLoopGroup = nettyConfig.getEventLoopGroup() == null; + eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyConfig.getEventLoopGroup(); + if (!(eventLoopGroup instanceof NioEventLoopGroup)) + throw new IllegalArgumentException("Only Nio is supported"); + + plainBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + secureBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + webSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + secureWebSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); + + if (config.getConnectionTimeout() > 0) + nettyConfig.addChannelOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectionTimeout()); + for (Entry, Object> entry : nettyConfig.propertiesSet()) { + ChannelOption key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.option(key, value); + webSocketBootstrap.option(key, value); + secureBootstrap.option(key, value); + secureWebSocketBootstrap.option(key, value); + } + } + + public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean closed) { + + HttpProtocol httpProtocol = new HttpProtocol(this, config, nettyConfig, requestSender); + final Processor httpProcessor = new Processor(config, this, requestSender, httpProtocol); + + WebSocketProtocol wsProtocol = new WebSocketProtocol(this, config, nettyConfig, requestSender); + wsProcessor = new Processor(config, this, requestSender, wsProtocol); + + plainBootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline().addLast(HTTP_HANDLER, newHttpClientCodec()); + + if (config.isCompressionEnabled()) { + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + } + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// + .addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpAdditionalChannelInitializer() != null) { + nettyConfig.getHttpAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + webSocketBootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline()// + .addLast(HTTP_HANDLER, newHttpClientCodec())// + .addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWsAdditionalChannelInitializer() != null) { + nettyConfig.getWsAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + secureBootstrap.handler(new ChannelInitializer() { + + @Override + protected void initChannel(Channel ch) throws Exception { + + ChannelPipeline pipeline = ch.pipeline()// + .addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); + + if (config.isCompressionEnabled()) { + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + } + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// + .addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpsAdditionalChannelInitializer() != null) { + nettyConfig.getHttpsAdditionalChannelInitializer().initChannel(ch); + } + } + }); + + secureWebSocketBootstrap.handler(new ChannelInitializer() { + + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline()// + .addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this))// + .addLast(HTTP_HANDLER, newHttpClientCodec())// + .addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWssAdditionalChannelInitializer() != null) { + nettyConfig.getWssAdditionalChannelInitializer().initChannel(ch); + } + } + }); } public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { @@ -110,26 +272,26 @@ 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; } 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.getDefaultAttribute(channel); if (attachment instanceof NettyResponseFuture) { @@ -137,13 +299,17 @@ public void destroy() { future.cancelTimeouts(); } } + + if (allowReleaseEventLoopGroup) + eventLoopGroup.shutdownGracefully(); } 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 if a timeout occurred, and + // this method may be called just after. if (channel != null) { LOGGER.debug("Closing Channel {} ", channel); try { @@ -165,4 +331,96 @@ public void abortChannelPreemption(String poolKey) { public void registerOpenChannel(Channel channel) { openChannels.add(channel); } -} \ No newline at end of file + + private HttpClientCodec newHttpClientCodec() { + return new HttpClientCodec(// + nettyConfig.getHttpClientCodecMaxInitialLineLength(),// + nettyConfig.getHttpClientCodecMaxHeaderSize(),// + nettyConfig.getHttpClientCodecMaxChunkSize(),// + false); + } + + public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { + + 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); + } + + SslHandler sslHandler = new SslHandler(sslEngine); + if (handshakeTimeoutInMillis > 0) + sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); + + return sslHandler; + } + + 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) { + 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()); + + if (isWebSocket(scheme)) + pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + } + + public String getPoolKey(NettyResponseFuture future) { + return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); + } + + /** + * 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. + */ + 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 Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSSl) { + return uri.getScheme().startsWith(WEBSOCKET) && !useProxy ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : // + (useSSl ? secureBootstrap : plainBootstrap); + } + + 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)); + } + + public final Callback newDrainCallback(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, final String poolKey) { + + return new Callback(future) { + public void call() throws Exception { + tryToOfferChannelToPool(channel, keepAlive, poolKey); + } + }; + } + + public void drainChannel(final Channel channel, final NettyResponseFuture future) { + Channels.setDefaultAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + } +} diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java old mode 100644 new mode 100755 index 304d2d7931..eda10d57d9 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -1,409 +1,29 @@ /* - * 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 org.asynchttpclient.providers.netty.channel; -import static org.asynchttpclient.providers.netty.handler.Processor.newHttpProcessor; -import static org.asynchttpclient.providers.netty.handler.Processor.newWsProcessor; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; - -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.channel.pool.DefaultChannelPool; -import org.asynchttpclient.providers.netty.channel.pool.NoopChannelPool; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.handler.Processor; -import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.SslUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpContentDecompressor; -import io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; -import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; import io.netty.handler.ssl.SslHandler; -import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.util.Attribute; import io.netty.util.AttributeKey; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timeout; -import io.netty.util.Timer; -import io.netty.util.TimerTask; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.DiscardEvent; public class Channels { - private static final Logger LOGGER = LoggerFactory.getLogger(Channels.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"; - 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 static final AttributeKey DEFAULT_ATTRIBUTE = AttributeKey.valueOf("default"); - private final AsyncHttpClientConfig config; - private final NettyAsyncHttpProviderConfig nettyProviderConfig; - - private final EventLoopGroup eventLoopGroup; - private final boolean allowReleaseEventLoopGroup; - - private final Bootstrap plainBootstrap; - private final Bootstrap secureBootstrap; - private final Bootstrap webSocketBootstrap; - private final Bootstrap secureWebSocketBootstrap; - - public final ChannelManager channelManager; - private final boolean allowStopNettyTimer; - private final Timer nettyTimer; - private final long handshakeTimeoutInMillis; - - private Processor wsProcessor; - - public Channels(final AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyProviderConfig) { - - this.config = config; - this.nettyProviderConfig = nettyProviderConfig; - - // check if external EventLoopGroup is defined - allowReleaseEventLoopGroup = nettyProviderConfig.getEventLoopGroup() == null; - eventLoopGroup = allowReleaseEventLoopGroup ? new NioEventLoopGroup() : nettyProviderConfig.getEventLoopGroup(); - - // check if external HashedWheelTimer is defined - allowStopNettyTimer = nettyProviderConfig.getNettyTimer() == null; - nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyProviderConfig.getNettyTimer(); - handshakeTimeoutInMillis = nettyProviderConfig.getHandshakeTimeoutInMillis(); - - if (!(eventLoopGroup instanceof NioEventLoopGroup)) - throw new IllegalArgumentException("Only Nio is supported"); - - plainBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - secureBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - webSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - secureWebSocketBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(eventLoopGroup); - - ChannelPool cp = nettyProviderConfig.getChannelPool(); - if (cp == null) { - if (config.isAllowPoolingConnections()) { - cp = new DefaultChannelPool(config, nettyTimer); - } else { - cp = new NoopChannelPool(); - } - } - this.channelManager = new ChannelManager(config, cp); - - for (Entry, Object> entry : nettyProviderConfig.propertiesSet()) { - ChannelOption key = entry.getKey(); - Object value = entry.getValue(); - plainBootstrap.option(key, value); - webSocketBootstrap.option(key, value); - secureBootstrap.option(key, value); - secureWebSocketBootstrap.option(key, value); - } - - int timeOut = config.getConnectionTimeout() > 0 ? config.getConnectionTimeout() : Integer.MAX_VALUE; - plainBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - webSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - secureBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - secureWebSocketBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeOut); - } - - private Timer newNettyTimer() { - HashedWheelTimer nettyTimer = new HashedWheelTimer(); - nettyTimer.start(); - return nettyTimer; - } - - public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException { - - SSLEngine sslEngine = null; - if (nettyProviderConfig.getSslEngineFactory() != null) { - sslEngine = nettyProviderConfig.getSslEngineFactory().newSSLEngine(); - - } else { - SSLContext sslContext = config.getSSLContext(); - if (sslContext == null) - sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); - - sslEngine = sslContext.createSSLEngine(peerHost, peerPort); - sslEngine.setUseClientMode(true); - } - - SslHandler sslHandler = new SslHandler(sslEngine); - if (handshakeTimeoutInMillis > 0) - sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); - - return sslHandler; - } - - public void configureProcessor(NettyRequestSender requestSender, AtomicBoolean closed) { - - final Processor httpProcessor = newHttpProcessor(config, nettyProviderConfig, requestSender, this, closed); - wsProcessor = newWsProcessor(config, nettyProviderConfig, requestSender, this, closed); - - plainBootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline().addLast(HTTP_HANDLER, newHttpClientCodec()); - - if (config.isCompressionEnabled()) { - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); - } - pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// - .addLast(HTTP_PROCESSOR, httpProcessor); - - if (nettyProviderConfig.getHttpAdditionalChannelInitializer() != null) { - nettyProviderConfig.getHttpAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - webSocketBootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline()// - .addLast(HTTP_HANDLER, newHttpClientCodec())// - .addLast(WS_PROCESSOR, wsProcessor); - - if (nettyProviderConfig.getWsAdditionalChannelInitializer() != null) { - nettyProviderConfig.getWsAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - secureBootstrap.handler(new ChannelInitializer() { - - @Override - protected void initChannel(Channel ch) throws Exception { - - ChannelPipeline pipeline = ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this)).addLast(HTTP_HANDLER, newHttpClientCodec()); - - if (config.isCompressionEnabled()) { - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); - } - pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler())// - .addLast(HTTP_PROCESSOR, httpProcessor); - - if (nettyProviderConfig.getHttpsAdditionalChannelInitializer() != null) { - nettyProviderConfig.getHttpsAdditionalChannelInitializer().initChannel(ch); - } - } - }); - - secureWebSocketBootstrap.handler(new ChannelInitializer() { - - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline()// - .addLast(SSL_HANDLER, new SslInitializer(Channels.this))// - .addLast(HTTP_HANDLER, newHttpClientCodec())// - .addLast(WS_PROCESSOR, wsProcessor); - - if (nettyProviderConfig.getWssAdditionalChannelInitializer() != null) { - nettyProviderConfig.getWssAdditionalChannelInitializer().initChannel(ch); - } - } - }); - } - - public Bootstrap getBootstrap(UriComponents uri, boolean useSSl, boolean useProxy) { - return (uri.getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) - : (useSSl ? secureBootstrap : plainBootstrap); - } - - public void close() { - channelManager.destroy(); - - if (allowReleaseEventLoopGroup) - eventLoopGroup.shutdownGracefully(); - - if (allowStopNettyTimer) - nettyTimer.stop(); - } - - /** - * 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. - */ - 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(Channels.this)); - } - - protected HttpClientCodec newHttpClientCodec() { - if (nettyProviderConfig != null) { - return new HttpClientCodec(// - nettyProviderConfig.getMaxInitialLineLength(),// - nettyProviderConfig.getMaxHeaderSize(),// - nettyProviderConfig.getMaxChunkSize(),// - false); - - } else { - return new HttpClientCodec(); - } - } - - public 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, newHttpClientCodec()); - p.addFirst(SSL_HANDLER, createSslHandler(host, port)); - } else { - p.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); - } - - } else { - p.addFirst(HTTP_HANDLER, newHttpClientCodec()); - } - - if (isWebSocket(scheme)) { - p.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); - } - } - - public static void upgradePipelineForWebSockets(Channel channel) { - channel.pipeline().replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); - channel.pipeline().addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); - } - - 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); - - try { - verifyChannelPipeline(channel.pipeline(), uri.getScheme()); - } catch (Exception ex) { - LOGGER.debug(ex.getMessage(), ex); - } - } - return channel; - } - - 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; - } - - public void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - } - - public void abortChannelPreemption(String poolKey) { - channelManager.abortChannelPreemption(poolKey); - } - - public void closeChannel(Channel channel) { - channelManager.closeChannel(channel); - } - - public final Callable> newDrainCallable(final NettyResponseFuture future, final Channel channel, - final boolean keepAlive, final String poolKey) { - - return new Callable>() { - public NettyResponseFuture call() throws Exception { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - return null; - } - }; - } - - public void drainChannel(final Channel channel, final NettyResponseFuture future) { - setDefaultAttribute(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); - } - - public String getPoolKey(NettyResponseFuture future) { - return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); - } - - public void removeAll(Channel channel) { - channelManager.removeAll(channel); - } - - 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 newTimeoutInMs(TimerTask task, long delayInMs) { - return nettyTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); - } - public static SslHandler getSslHandler(Channel channel) { return channel.pipeline().get(SslHandler.class); } @@ -420,8 +40,8 @@ public static void setDefaultAttribute(Channel channel, Object o) { public static void setDiscard(Channel channel) { setDefaultAttribute(channel, DiscardEvent.INSTANCE); } - - public void registerOpenChannel(Channel channel) { - channelManager.registerOpenChannel(channel); + + public static boolean isChannelValid(Channel channel) { + return channel != null && channel.isOpen() && channel.isActive(); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java old mode 100644 new mode 100755 similarity index 98% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java index 853ea319e9..edd0c2643a --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/CleanupChannelGroup.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/CleanupChannelGroup.java @@ -25,7 +25,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asynchttpclient.providers.netty.util; +package org.asynchttpclient.providers.netty.channel; import io.netty.channel.Channel; import io.netty.channel.group.ChannelGroupFuture; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java old mode 100644 new mode 100755 index e0df603cd0..31819ee86b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -30,10 +30,10 @@ */ public class SslInitializer extends ChannelOutboundHandlerAdapter { - private final Channels channels; + private final ChannelManager channelManager; - public SslInitializer(Channels channels) { - this.channels = channels; + public SslInitializer(ChannelManager channelManager) { + this.channelManager = channelManager; } @Override @@ -44,9 +44,9 @@ public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, Sock String peerHost = remoteInetSocketAddress.getHostName(); int peerPort = remoteInetSocketAddress.getPort(); - SslHandler sslHandler = channels.createSslHandler(peerHost, peerPort); + SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); - ctx.pipeline().replace(Channels.SSL_HANDLER, Channels.SSL_HANDLER, sslHandler); + ctx.pipeline().replace(ChannelManager.SSL_HANDLER, ChannelManager.SSL_HANDLER, sslHandler); ctx.connect(remoteAddress, localAddress, promise); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java old mode 100644 new mode 100755 index 4f1d96ba16..ef1fbd9973 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/ChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/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 org.asynchttpclient.providers.netty.channel.pool; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java old mode 100644 new mode 100755 index f8d684ad84..ad7fe1ccb3 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/NoopChannelPool.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 org.asynchttpclient.providers.netty.channel.pool; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java index 9d2a692f77..ab5a1f04e9 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/NettyResponseFuture.java @@ -1,35 +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 org.asynchttpclient.providers.netty.future; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.AsyncHandler; -import org.asynchttpclient.ConnectionPoolKeyStrategy; -import org.asynchttpclient.ProxyServer; -import org.asynchttpclient.Request; -import org.asynchttpclient.listenable.AbstractListenableFuture; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.request.NettyRequest; -import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; -import org.asynchttpclient.uri.UriComponents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; @@ -46,6 +30,18 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.ConnectionPoolKeyStrategy; +import org.asynchttpclient.ProxyServer; +import org.asynchttpclient.Request; +import org.asynchttpclient.listenable.AbstractListenableFuture; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.request.NettyRequest; +import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; +import org.asynchttpclient.uri.UriComponents; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. * @@ -137,7 +133,7 @@ public boolean cancel(boolean force) { return false; try { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setDiscard(channel); channel.close(); } catch (Throwable t) { // Ignore @@ -452,8 +448,8 @@ public void setRequest(Request request) { * @return true if that {@link Future} cannot be recovered. */ public boolean canBeReplayed() { - return !isDone() && canRetry() && !isCancelled() - && !(channel != null && channel.isOpen() && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); + return !isDone() && canRetry() + && !(Channels.isChannelValid(channel) && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); } public long getStart() { @@ -474,7 +470,7 @@ public String toString() { ",\n\thttpHeaders=" + httpHeaders + // ",\n\texEx=" + exEx + // ",\n\tredirectCount=" + redirectCount + // - ",\n\timeoutsHolder=" + timeoutsHolder + // + ",\n\ttimeoutsHolder=" + timeoutsHolder + // ",\n\tinAuth=" + inAuth + // ",\n\tstatusReceived=" + statusReceived + // ",\n\ttouch=" + touch + // diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/future/StackTraceInspector.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java old mode 100644 new mode 100755 index 377dd130cd..380121278c --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.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 org.asynchttpclient.providers.netty.handler; @@ -19,16 +17,25 @@ import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; + +import java.io.IOException; +import java.util.List; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandler.STATE; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.ProxyServer; import org.asynchttpclient.Realm; import org.asynchttpclient.Request; @@ -37,6 +44,7 @@ import org.asynchttpclient.ntlm.NTLMEngineException; import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequest; @@ -46,37 +54,19 @@ import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpContent; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; -import java.io.IOException; -import java.util.List; - -final class HttpProtocol extends Protocol { +public final class HttpProtocol extends Protocol { - private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); - - public HttpProtocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, - NettyRequestSender requestSender) { - super(channels, config, nettyConfig, requestSender); + public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { + super(channelManager, config, nettyConfig, requestSender); } 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) 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 ? uri.getHost() : request.getVirtualHost(); @@ -96,21 +86,21 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); } - channels.abort(future, throwable); + requestSender.abort(future, throwable); return null; } } 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 addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } - 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; @@ -143,13 +133,12 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p } } - private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, 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(), proxyInd); + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd); return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) @@ -157,8 +146,8 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer .setMethodName(request.getMethod()).build(); } - 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)); if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { @@ -172,19 +161,17 @@ private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean keepAlive = future.isKeepAlive(); if (expectOtherChunks && keepAlive) - channels.drainChannel(channel, future); + channelManager.drainChannel(channel, future); else - channels.tryToOfferChannelToPool(channel, keepAlive, channels.getPoolKey(future)); + channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); markAsDone(future, channel); } - private final boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart bodyPart) - throws Exception { - boolean state = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; - if (bodyPart.isUnderlyingConnectionToBeClosed()) { + private boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, NettyResponseBodyPart bodyPart) throws Exception { + boolean interrupt = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; + if (bodyPart.isUnderlyingConnectionToBeClosed()) future.setKeepAlive(false); - } - return state; + return interrupt; } private void markAsDone(NettyResponseFuture future, final Channel channel) { @@ -194,33 +181,39 @@ private void markAsDone(NettyResponseFuture future, final Channel channel) { future.done(); } catch (Throwable t) { // Never propagate exception once we know we are done. - LOGGER.debug(t.getMessage(), t); + logger.debug(t.getMessage(), t); } if (!future.isKeepAlive() || !channel.isActive()) { - channels.closeChannel(channel); + channelManager.closeChannel(channel); } } - private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Request request, HttpResponse response, - final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws Exception { - if (statusCode == UNAUTHORIZED.code() && realm != null) { + private boolean exitAfterHandling401(// + final Channel channel,// + final NettyResponseFuture future,// + HttpResponse response,// + final Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer) throws Exception { + + if (statusCode == UNAUTHORIZED.code() && realm != null && !future.getAndSetAuth(true)) { - List authenticateHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); + List wwwAuthHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); - if (!authenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { + if (!wwwAuthHeaders.isEmpty()) { future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; - // NTLM - boolean negociate = authenticateHeaders.contains("Negotiate"); - if (!authenticateHeaders.contains("Kerberos") && (isNTLM(authenticateHeaders) || negociate)) { - newRealm = ntlmChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); - // SPNEGO KERBEROS + boolean negociate = wwwAuthHeaders.contains("Negotiate"); + if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { + // NTLM + newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); } else if (negociate) { - newRealm = kerberosChallenge(authenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, false); - if (newRealm == null) { + newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); + // SPNEGO KERBEROS + if (newRealm == null) return true; - } } else { newRealm = new Realm.RealmBuilder()// .clone(realm)// @@ -228,28 +221,27 @@ private boolean handleUnauthorizedAndExit(int statusCode, Realm realm, final Req .setUri(request.getURI())// .setMethodName(request.getMethod())// .setUsePreemptiveAuth(true)// - .parseWWWAuthenticateHeader(authenticateHeaders.get(0))// + .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// .build(); } Realm nr = newRealm; final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).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 { - channels.drainChannel(channel, future); + channelManager.drainChannel(channel, future); requestSender.sendNextRequest(nextRequest, future); } }; - if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) { + if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) // We must make sure there is no bytes left // before executing the next request. Channels.setDefaultAttribute(channel, callback); - } else { + else callback.call(); - } return true; } @@ -258,7 +250,7 @@ public void call() throws Exception { return false; } - private boolean handleContinueAndExit(final Channel channel, final NettyResponseFuture future, int statusCode) { + private boolean exitAfterHandling100(final Channel channel, final NettyResponseFuture future, int statusCode) { if (statusCode == CONTINUE.code()) { future.setHeadersAlreadyWrittenOnContinue(true); future.setDontWriteBodyBecauseExpectContinue(false); @@ -270,27 +262,31 @@ private boolean handleContinueAndExit(final Channel channel, final NettyResponse return false; } - private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// - Realm realm,// - final Request request,// + private boolean exitAfterHandling407(// + NettyResponseFuture future,// HttpResponse response,// - final NettyResponseFuture future,// + Request request,// + int statusCode,// + Realm realm,// ProxyServer proxyServer) throws Exception { - if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null) { - List proxyAuthenticateHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); - if (!proxyAuthenticateHeaders.isEmpty() && !future.getAndSetAuth(true)) { - LOGGER.debug("Sending proxy authentication to {}", request.getURI()); + if (statusCode == PROXY_AUTHENTICATION_REQUIRED.code() && realm != null && !future.getAndSetAuth(true)) { + + List proxyAuthHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); + + if (!proxyAuthHeaders.isEmpty()) { + logger.debug("Sending proxy authentication to {}", request.getURI()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - boolean negociate = proxyAuthenticateHeaders.contains("Negotiate"); - if (!proxyAuthenticateHeaders.contains("Kerberos") && (isNTLM(proxyAuthenticateHeaders) || negociate)) { - newRealm = ntlmProxyChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); + 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 (negociate) { - newRealm = kerberosChallenge(proxyAuthenticateHeaders, request, proxyServer, request.getHeaders(), realm, future, true); + newRealm = kerberosChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); if (newRealm == null) return true; } else { @@ -300,13 +296,13 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// .setOmitQuery(true)// .setMethodName(HttpMethod.CONNECT.name())// .setUsePreemptiveAuth(true)// - .parseProxyAuthenticateHeader(proxyAuthenticateHeaders.get(0))// + .parseProxyAuthenticateHeader(proxyAuthHeaders.get(0))// .build(); } future.setReuseChannel(true); future.setConnectAllowed(true); - Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(newRealm).build(); + Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(newRealm).build(); requestSender.sendNextRequest(nextRequest, future); return true; } @@ -314,27 +310,32 @@ private boolean handleProxyAuthenticationRequiredAndExit(int statusCode,// return false; } - private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Request request, HttpRequest httpRequest, - HttpResponse response, final NettyResponseFuture future, ProxyServer proxyServer, final Channel channel) throws IOException { - if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { + private boolean exitAfterHandlingConnect(// + final Channel channel,// + final NettyResponseFuture future,// + final Request request,// + ProxyServer proxyServer,// + int statusCode,// + HttpRequest httpRequest) throws IOException { - LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); + if (statusCode == OK.code() && httpRequest.getMethod() == HttpMethod.CONNECT) { - if (future.isKeepAlive()) { + if (future.isKeepAlive()) future.attachChannel(channel, true); - } try { UriComponents requestURI = request.getURI(); String scheme = requestURI.getScheme(); - LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); String host = requestURI.getHost(); - int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); - - channels.upgradeProtocol(channel.pipeline(), scheme, host, port); + int port = getDefaultPort(requestURI); + + logger.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + channelManager.upgradeProtocol(channel.pipeline(), scheme, host, port); + } catch (Throwable ex) { - channels.abort(future, ex); + requestSender.abort(future, ex); } + future.setReuseChannel(true); future.setConnectAllowed(false); requestSender.sendNextRequest(new RequestBuilder(future.getRequest()).build(), future); @@ -344,18 +345,29 @@ private boolean handleConnectOKAndExit(int statusCode, Realm realm, final Reques return false; } - private boolean handleHanderAndExit(Channel channel, NettyResponseFuture future, AsyncHandler handler, HttpResponseStatus status, - HttpResponseHeaders responseHeaders, HttpResponse response) throws Exception { - if (!future.getAndSetStatusReceived(true) - && (handler.onStatusReceived(status) != STATE.CONTINUE || handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE)) { + 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 boolean handleResponseAndExit(final Channel channel, final NettyResponseFuture future, AsyncHandler handler, - HttpRequest httpRequest, ProxyServer proxyServer, HttpResponse response) throws Exception { + 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 boolean handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, AsyncHandler handler) throws Exception { + + HttpRequest httpRequest = future.getNettyRequest().getHttpRequest(); + ProxyServer proxyServer = future.getProxyServer(); + logger.debug("\n\nRequest {}\n\nResponse {}\n", httpRequest, response); // store the original headers so we can re-send all them to // the handler in case of trailing headers @@ -363,19 +375,20 @@ private boolean handleResponseAndExit(final Channel channel, final NettyResponse future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); - HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config); + ResponseStatus status = new ResponseStatus(future.getURI(), config, response); int statusCode = response.getStatus().code(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - - return handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)// - || handleUnauthorizedAndExit(statusCode, realm, request, response, future, proxyServer, channel)// - || handleContinueAndExit(channel, future, statusCode)// - || handleProxyAuthenticationRequiredAndExit(statusCode, realm, request, response, future, proxyServer) - || handleConnectOKAndExit(statusCode, realm, request, httpRequest, response, future, proxyServer, channel)// - || handleRedirectAndExit(request, future, response, channel)// - || handleHanderAndExit(channel, future, handler, status, responseHeaders, response); + ResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + + 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, response, request, statusCode) || // + exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, httpRequest) || // + exitAfterHandlingStatus(channel, future, response, handler, status) || // + exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders); } @Override @@ -385,59 +398,54 @@ public void handle(final Channel channel, final NettyResponseFuture future, f // The connect timeout occurred. if (future.isDone()) { - channels.closeChannel(channel); + channelManager.closeChannel(channel); return; } NettyRequest nettyRequest = future.getNettyRequest(); AsyncHandler handler = future.getAsyncHandler(); - ProxyServer proxyServer = future.getProxyServer(); try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); + logger.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); + // FIXME why do we buffer the response? I don't remember... future.setPendingResponse(response); return; - } - if (e instanceof HttpContent) { + } else if (e instanceof HttpContent) { HttpResponse response = future.getPendingResponse(); future.setPendingResponse(null); - if (handler != null) { - if (response != null - && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest(), proxyServer, response)) { - return; - } + if (response != null && handleHttpResponse(response, channel, future, handler)) + return; - HttpContent chunk = (HttpContent) e; + HttpContent chunk = (HttpContent) e; - boolean interrupt = false; - boolean last = chunk instanceof LastHttpContent; + boolean interrupt = false; + boolean last = chunk instanceof LastHttpContent; - if (last) { - LastHttpContent lastChunk = (LastHttpContent) chunk; - HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); - if (!trailingHeaders.isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); - interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; - } - } - - ByteBuf buf = chunk.content(); - try { - if (!interrupt && (buf.readableBytes() > 0 || last)) { - NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); - interrupt = updateBodyAndInterrupt(future, handler, part); - } - } finally { - // FIXME we shouldn't need this, should we? But a leak was reported there without it?! - buf.release(); + // Netty 4: the last chunk is not empty + if (last) { + LastHttpContent lastChunk = (LastHttpContent) chunk; + HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); + if (!trailingHeaders.isEmpty()) { + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); + interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } + } - if (interrupt || last) { - finishUpdate(future, channel, !last); + ByteBuf buf = chunk.content(); + try { + if (!interrupt && (buf.readableBytes() > 0 || last)) { + NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); + interrupt = updateBodyAndInterrupt(future, handler, part); } + } finally { + // FIXME we shouldn't need this, should we? But a leak was reported there without it?! + buf.release(); } + + if (interrupt || last) + finishUpdate(future, channel, !last); } } catch (Exception t) { if (hasIOExceptionFilters// @@ -447,9 +455,9 @@ && handleResponseAndExit(channel, future, handler, nettyRequest.getHttpRequest() } try { - channels.abort(future, t); + requestSender.abort(future, t); } catch (Exception abortException) { - LOGGER.debug("Abort failed", abortException); + logger.debug("Abort failed", abortException); } finally { finishUpdate(future, channel, false); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java old mode 100644 new mode 100755 index f1d6a1d3e0..8cbd848de6 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -1,32 +1,19 @@ /* - * 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 org.asynchttpclient.providers.netty.handler; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.Callback; -import org.asynchttpclient.providers.netty.DiscardEvent; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.future.StackTraceInspector; -import org.asynchttpclient.providers.netty.request.NettyRequestSender; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import static org.asynchttpclient.util.AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; @@ -36,62 +23,57 @@ import java.io.IOException; import java.nio.channels.ClosedChannelException; -import java.util.concurrent.atomic.AtomicBoolean; + +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.Callback; +import org.asynchttpclient.providers.netty.DiscardEvent; +import org.asynchttpclient.providers.netty.channel.ChannelManager; +import org.asynchttpclient.providers.netty.channel.Channels; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.future.StackTraceInspector; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Sharable public class Processor extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class); + public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel Closed"); + static { + CHANNEL_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); + } + private final AsyncHttpClientConfig config; + private final ChannelManager channelManager; private final NettyRequestSender requestSender; - private final Channels channels; - private final AtomicBoolean closed; private final Protocol protocol; - public static Processor newHttpProcessor(AsyncHttpClientConfig config,// - NettyAsyncHttpProviderConfig nettyConfig,// - NettyRequestSender requestSender,// - Channels channels,// - AtomicBoolean isClose) { - HttpProtocol protocol = new HttpProtocol(channels, config, nettyConfig, requestSender); - return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); - } - - public static Processor newWsProcessor(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, - NettyRequestSender requestSender, Channels channels, AtomicBoolean isClose) { - WebSocketProtocol protocol = new WebSocketProtocol(channels, config, nettyConfig, requestSender); - return new Processor(config, nettyConfig, requestSender, channels, isClose, protocol); - } - - private Processor(AsyncHttpClientConfig config,// - NettyAsyncHttpProviderConfig nettyConfig,// + public Processor(AsyncHttpClientConfig config,// + ChannelManager channelManager,// NettyRequestSender requestSender,// - Channels channels,// - AtomicBoolean isClose,// Protocol protocol) { this.config = config; + this.channelManager = channelManager; this.requestSender = requestSender; - this.channels = channels; - this.closed = isClose; this.protocol = protocol; } @Override - public void channelRead(final ChannelHandlerContext ctx, Object e) throws Exception { + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { Channel channel = ctx.channel(); Object attribute = Channels.getDefaultAttribute(channel); - if (attribute instanceof Callback && e instanceof LastHttpContent) { + if (attribute instanceof Callback && msg instanceof LastHttpContent) { Callback ac = (Callback) attribute; ac.call(); Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); } else if (attribute instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attribute; - - protocol.handle(channel, future, e); + protocol.handle(channel, future, msg); } else if (attribute != DiscardEvent.INSTANCE) { try { @@ -104,9 +86,11 @@ public void channelRead(final ChannelHandlerContext ctx, Object e) throws Except public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (closed.get()) { + if (requestSender.isClosed()) return; - } + + Channel channel = ctx.channel(); + channelManager.removeAll(channel); try { super.channelInactive(ctx); @@ -114,8 +98,6 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { LOGGER.trace("super.channelClosed", ex); } - Channel channel = ctx.channel(); - channels.removeAll(channel); Object attachment = Channels.getDefaultAttribute(channel); LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); @@ -128,20 +110,16 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { NettyResponseFuture future = NettyResponseFuture.class.cast(attachment); future.touch(); - if (!config.getIOExceptionFilters().isEmpty() - && requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), channel)) { + if (!config.getIOExceptionFilters().isEmpty() && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) return; - } protocol.onClose(channel); - if (future != null && !future.isDone() && !future.isCancelled()) { - if (!requestSender.retry(future, channel)) { - channels.abort(future, AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); - } - } else { - channels.closeChannel(channel); - } + if (future == null || future.isDone()) + channelManager.closeChannel(channel); + + else if (!requestSender.retry(future, channel)) + requestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); } } @@ -149,9 +127,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { Throwable cause = e.getCause() != null ? e.getCause() : e; - if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) { + if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) return; - } Channel channel = ctx.channel(); NettyResponseFuture future = null; @@ -167,12 +144,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep if (cause instanceof IOException) { - // FIXME why drop the original exception and create a new one? - if (!config.getIOExceptionFilters().isEmpty()) { - if (requestSender.applyIoExceptionFiltersAndReplayRequest(future, new IOException("Channel Closed"), 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 { + else { // Close the channel so the recovering can occur try { channel.close(); @@ -194,18 +170,17 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep cause = t; } - if (future != null) { + if (future != null) try { LOGGER.debug("Was unable to recover Future: {}", future); - channels.abort(future, cause); + requestSender.abort(future, cause); } catch (Throwable t) { LOGGER.error(t.getMessage(), t); } - } protocol.onError(channel, e); - channels.closeChannel(channel); + channelManager.closeChannel(channel); // FIXME not really sure // ctx.fireChannelRead(e); ctx.close(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java old mode 100644 new mode 100755 index 59ff36c90e..8eb8363a47 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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 @@ -16,8 +17,16 @@ import static io.netty.handler.codec.http.HttpResponseStatus.MOVED_PERMANENTLY; import static io.netty.handler.codec.http.HttpResponseStatus.SEE_OTHER; import static io.netty.handler.codec.http.HttpResponseStatus.TEMPORARY_REDIRECT; -import static org.asynchttpclient.providers.netty.util.HttpUtil.HTTP; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.HTTP; +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.followRedirect; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponse; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHttpClientConfig; @@ -32,30 +41,21 @@ import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.FilterException; import org.asynchttpclient.filter.ResponseFilter; +import org.asynchttpclient.providers.netty.Callback; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpResponse; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.Callable; - public abstract class Protocol { - private final Logger logger = LoggerFactory.getLogger(getClass()); + protected final Logger logger = LoggerFactory.getLogger(getClass()); - protected final Channels channels; + protected final ChannelManager channelManager; protected final AsyncHttpClientConfig config; protected final NettyAsyncHttpProviderConfig nettyConfig; protected final NettyRequestSender requestSender; @@ -64,18 +64,17 @@ public abstract class Protocol { protected final boolean hasIOExceptionFilters; private final TimeConverter timeConverter; - public static final Set REDIRECT_STATUSES = new HashSet(); - + public static final Set REDIRECT_STATUSES = new HashSet(); static { - REDIRECT_STATUSES.add(MOVED_PERMANENTLY); - REDIRECT_STATUSES.add(FOUND); - REDIRECT_STATUSES.add(SEE_OTHER); - REDIRECT_STATUSES.add(TEMPORARY_REDIRECT); + REDIRECT_STATUSES.add(MOVED_PERMANENTLY.code()); + REDIRECT_STATUSES.add(FOUND.code()); + REDIRECT_STATUSES.add(SEE_OTHER.code()); + REDIRECT_STATUSES.add(TEMPORARY_REDIRECT.code()); } - public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { - this.channels = channels; + this.channelManager = channelManager; this.config = config; this.requestSender = requestSender; this.nettyConfig = nettyConfig; @@ -91,12 +90,14 @@ public Protocol(Channels channels, AsyncHttpClientConfig config, NettyAsyncHttpP public abstract void onClose(Channel channel); - protected boolean handleRedirectAndExit(Request request, final NettyResponseFuture future, HttpResponse response, final Channel channel) - throws Exception { - - io.netty.handler.codec.http.HttpResponseStatus status = response.getStatus(); + protected boolean exitAfterHandlingRedirect(// + Channel channel,// + NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode) throws Exception { - if (AsyncHttpProviderUtils.followRedirect(config, request) && REDIRECT_STATUSES.contains(status)) { + if (followRedirect(config, request) && REDIRECT_STATUSES.contains(statusCode)) { if (future.incrementAndGetCurrentRedirectCount() >= config.getMaxRedirects()) { throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); @@ -104,7 +105,8 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu // We must allow 401 handling again. future.getAndSetAuth(false); - String location = response.headers().get(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())) { @@ -113,15 +115,14 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu if (!config.isRemoveQueryParamOnRedirect()) requestBuilder.addQueryParams(future.getRequest().getQueryParams()); - // FIXME why not do that for 301 and 307 too? - // FIXME I think condition is wrong - if ((status.equals(FOUND) || status.equals(SEE_OTHER)) && !(status.equals(FOUND) && config.isStrict302Handling())) { - requestBuilder.setMethod(HttpMethod.GET.name()); - } + // if we are to strictly handle 302, we should keep the original method (which browsers don't) + // 303 must force GET + if ((statusCode == FOUND.code() && !config.isStrict302Handling()) || statusCode == SEE_OTHER.code()) + requestBuilder.setMethod("GET"); // in case of a redirect from HTTP to HTTPS, future attributes might change final boolean initialConnectionKeepAlive = future.isKeepAlive(); - final String initialPoolKey = channels.getPoolKey(future); + final String initialPoolKey = channelManager.getPoolKey(future); future.setURI(uri); String newUrl = uri.toString(); @@ -131,23 +132,13 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu logger.debug("Redirecting to {}", newUrl); - if (future.getHttpHeaders().contains(HttpHeaders.Names.SET_COOKIE2)) { - for (String cookieStr : future.getHttpHeaders().getAll(HttpHeaders.Names.SET_COOKIE2)) { - Cookie c = CookieDecoder.decode(cookieStr, timeConverter); - if (c != null) { - requestBuilder.addOrReplaceCookie(c); - } - } - } else if (future.getHttpHeaders().contains(HttpHeaders.Names.SET_COOKIE)) { - for (String cookieStr : future.getHttpHeaders().getAll(HttpHeaders.Names.SET_COOKIE)) { - Cookie c = CookieDecoder.decode(cookieStr, timeConverter); - if (c != null) { - requestBuilder.addOrReplaceCookie(c); - } - } + for (String cookieStr : responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE)) { + Cookie c = CookieDecoder.decode(cookieStr, timeConverter); + if (c != null) + requestBuilder.addOrReplaceCookie(c); } - Callable> callback = channels.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); + Callback callback = channelManager.newDrainCallback(future, channel, initialConnectionKeepAlive, initialPoolKey); if (HttpHeaders.isTransferEncodingChunked(response)) { // We must make sure there is no bytes left before @@ -170,14 +161,15 @@ protected boolean handleRedirectAndExit(Request request, final NettyResponseFutu return false; } - protected boolean handleResponseFiltersReplayRequestAndExit(// + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected boolean exitAfterProcessingFilters(// Channel channel,// NettyResponseFuture future,// + AsyncHandler handler, // HttpResponseStatus status,// HttpResponseHeaders responseHeaders) throws IOException { if (hasResponseFilters) { - AsyncHandler handler = future.getAsyncHandler(); FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) .responseStatus(status).responseHeaders(responseHeaders).build(); @@ -189,7 +181,7 @@ protected boolean handleResponseFiltersReplayRequestAndExit(// throw new NullPointerException("FilterContext is null"); } } catch (FilterException efe) { - channels.abort(future, efe); + requestSender.abort(future, efe); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java old mode 100644 new mode 100755 index 5aa2ce0663..8859822341 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -1,21 +1,31 @@ /* - * 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 org.asynchttpclient.providers.netty.handler; import static io.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS; +import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getAcceptKey; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; + +import java.io.IOException; +import java.util.Locale; import org.asynchttpclient.AsyncHandler.STATE; import org.asynchttpclient.AsyncHttpClientConfig; @@ -24,6 +34,7 @@ import org.asynchttpclient.Request; import org.asynchttpclient.providers.netty.DiscardEvent; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; @@ -31,33 +42,16 @@ import org.asynchttpclient.providers.netty.response.ResponseHeaders; import org.asynchttpclient.providers.netty.response.ResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; -import org.asynchttpclient.providers.netty.ws.WebSocketUtil; import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; +public final class WebSocketProtocol extends Protocol { -import java.io.IOException; -import java.util.Locale; - -final class WebSocketProtocol extends Protocol { - - private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); - - public WebSocketProtocol(Channels channels,// + public WebSocketProtocol(ChannelManager channelManager,// AsyncHttpClientConfig config,// NettyAsyncHttpProviderConfig nettyConfig,// NettyRequestSender requestSender) { - super(channels, config, nettyConfig, requestSender); + super(channelManager, config, nettyConfig, requestSender); } // We don't need to synchronize as replacing the "ws-decoder" will @@ -67,27 +61,27 @@ private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { try { h.onSuccess(new NettyWebSocket(channel)); } catch (Exception ex) { - LOGGER.warn("onSuccess unexpected exception", ex); + logger.warn("onSuccess unexpected exception", ex); } } } @Override public void handle(Channel channel, NettyResponseFuture future, Object e) throws Exception { - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); + WebSocketUpgradeHandler handler = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); Request request = future.getRequest(); if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config); + HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - if (handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders)) { + if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { return; } future.setHttpHeaders(response.headers()); - if (handleRedirectAndExit(request, future, response, channel)) + if (exitAfterHandlingRedirect(channel, future, response, request, response.getStatus().code())) return; boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS); @@ -99,45 +93,45 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - status = new ResponseStatus(future.getURI(), response, config); - final boolean statusReceived = h.onStatusReceived(status) == STATE.UPGRADE; + status = new ResponseStatus(future.getURI(), config, response); + final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { try { - h.onCompleted(); + handler.onCompleted(); } finally { future.done(); } return; } - final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + final boolean headerOK = handler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { - channels.abort(future, new IOException("Invalid handshake response")); + requestSender.abort(future, new IOException("Invalid handshake response")); return; } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHttpRequest().headers() + String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers() .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { - channels.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); + requestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } - Channels.upgradePipelineForWebSockets(channel); + channelManager.upgradePipelineForWebSockets(channel.pipeline()); - invokeOnSucces(channel, h); + invokeOnSucces(channel, handler); future.done(); } else if (e instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e; - NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - invokeOnSucces(channel, h); + NettyWebSocket webSocket = NettyWebSocket.class.cast(handler.onCompleted()); + invokeOnSucces(channel, handler); if (webSocket != null) { if (frame instanceof CloseWebSocketFrame) { - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setDiscard(channel); CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame); webSocket.onClose(closeFrame.statusCode(), closeFrame.reasonText()); } else { @@ -145,7 +139,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (buf != null && buf.readableBytes() > 0) { try { NettyResponseBodyPart rp = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, frame.isFinalFragment()); - h.onBodyPartReceived(rp); + handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); @@ -158,12 +152,12 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } } } else { - LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); + logger.debug("UpgradeHandler returned a null NettyWebSocket "); } } else if (e instanceof LastHttpContent) { // FIXME what to do with this kind of messages? } else { - LOGGER.error("Invalid message {}", e); + logger.error("Invalid message {}", e); } } @@ -171,7 +165,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr public void onError(Channel channel, Throwable e) { try { Object attribute = Channels.getDefaultAttribute(channel); - LOGGER.warn("onError {}", e); + logger.warn("onError {}", e); if (!(attribute instanceof NettyResponseFuture)) { return; } @@ -185,17 +179,16 @@ public void onError(Channel channel, Throwable e) { webSocket.close(); } } catch (Throwable t) { - LOGGER.error("onError", t); + logger.error("onError", t); } } @Override public void onClose(Channel channel) { - LOGGER.trace("onClose {}"); + logger.trace("onClose {}"); Object attribute = Channels.getDefaultAttribute(channel); - if (!(attribute instanceof NettyResponseFuture)) { + if (!(attribute instanceof NettyResponseFuture)) return; - } try { NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(attribute); @@ -203,11 +196,11 @@ public void onClose(Channel channel) { 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)."); + 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); + logger.error("onError", t); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java old mode 100644 new mode 100755 index c1ca441e1f..b4254bc088 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -1,24 +1,23 @@ /* - * 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 org.asynchttpclient.providers.netty.request; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; + import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.future.StackTraceInspector; @@ -34,6 +33,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; + import java.net.ConnectException; import java.nio.channels.ClosedChannelException; @@ -47,27 +47,27 @@ final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyRequestSender requestSender; private final NettyResponseFuture future; - private final Channels channels; + private final ChannelManager channelManager; private final boolean channelPreempted; private final String poolKey; public NettyConnectListener(AsyncHttpClientConfig config,// - NettyRequestSender requestSender,// NettyResponseFuture future,// - Channels channels,// + NettyRequestSender requestSender,// + ChannelManager channelManager,// boolean channelPreempted,// String poolKey) { - this.requestSender = requestSender; this.config = config; this.future = future; - this.channels = channels; + this.requestSender = requestSender; + this.channelManager = channelManager; this.channelPreempted = channelPreempted; this.poolKey = poolKey; } private void abortChannelPreemption(String poolKey) { if (channelPreempted) - channels.abortChannelPreemption(poolKey); + channelManager.abortChannelPreemption(poolKey); } private void writeRequest(Channel channel) { @@ -79,7 +79,7 @@ private void writeRequest(Channel channel) { return; } - channels.registerOpenChannel(channel); + channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); requestSender.writeRequest(future, channel); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java old mode 100644 new mode 100755 index 11eea6d69a..aec5d2fd03 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequest.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 org.asynchttpclient.providers.netty.request; @@ -19,7 +17,7 @@ import io.netty.handler.codec.http.HttpRequest; -public class NettyRequest { +public final class NettyRequest { private final HttpRequest httpRequest; private final NettyBody body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java old mode 100644 new mode 100755 index 55bbc81b85..2b26b06e2e --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -1,25 +1,29 @@ /* - * 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 org.asynchttpclient.providers.netty.request; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isNTLM; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isWebSocket; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getKey; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.constructUserAgent; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.keepAliveHeaderValue; +import static org.asynchttpclient.util.AuthenticatorUtils.computeBasicAuthentication; +import static org.asynchttpclient.util.AuthenticatorUtils.computeDigestAuthentication; import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpRequest; @@ -53,11 +57,8 @@ import org.asynchttpclient.providers.netty.request.body.NettyFileBody; import org.asynchttpclient.providers.netty.request.body.NettyInputStreamBody; import org.asynchttpclient.providers.netty.request.body.NettyMultipartBody; -import org.asynchttpclient.providers.netty.ws.WebSocketUtil; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.AuthenticatorUtils; import org.asynchttpclient.util.UTF8UrlEncoder; public final class NettyRequestFactory { @@ -74,7 +75,7 @@ public NettyRequestFactory(AsyncHttpClientConfig config, NettyAsyncHttpProviderC private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod method) { if (method == HttpMethod.CONNECT) - return AsyncHttpProviderUtils.getAuthority(uri); + return getAuthority(uri); else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) return uri.toString(); @@ -101,12 +102,12 @@ private String authorizationHeader(Request request, UriComponents uri, ProxyServ switch (realm.getAuthScheme()) { case BASIC: - authorizationHeader = AuthenticatorUtils.computeBasicAuthentication(realm); + authorizationHeader = computeBasicAuthentication(realm); break; case DIGEST: if (isNonEmpty(realm.getNonce())) { try { - authorizationHeader = AuthenticatorUtils.computeDigestAuthentication(realm); + authorizationHeader = computeDigestAuthentication(realm); } catch (NoSuchAlgorithmException e) { throw new SecurityException(e); } @@ -177,7 +178,7 @@ private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer } } } else { - proxyAuthorization = AuthenticatorUtils.computeBasicAuthentication(proxyServer); + proxyAuthorization = computeBasicAuthentication(proxyServer); } } @@ -228,8 +229,7 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { } else if (request.getBodyGenerator() instanceof FileBodyGenerator) { FileBodyGenerator fileBodyGenerator = (FileBodyGenerator) request.getBodyGenerator(); - nettyBody = new NettyFileBody(fileBodyGenerator.getFile(), fileBodyGenerator.getRegionSeek(), - fileBodyGenerator.getRegionLength(), nettyConfig); + 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()); @@ -295,13 +295,12 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean if (method != HttpMethod.CONNECT && webSocket) { httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); httpRequest.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - httpRequest.headers().set(HttpHeaders.Names.ORIGIN, - "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); + httpRequest.headers().set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); + httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey()); httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); } String hostHeader = hostHeader(request, uri); @@ -324,8 +323,7 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean // Add default user agent if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { - String userAgent = config.getUserAgent() != null ? config.getUserAgent() : AsyncHttpProviderUtils.constructUserAgent( - NettyAsyncHttpProvider.class, config); + String userAgent = config.getUserAgent() != null ? config.getUserAgent() : constructUserAgent(NettyAsyncHttpProvider.class, config); httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java old mode 100644 new mode 100755 index 79b76edb3d..5dd4ee7674 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -1,22 +1,40 @@ /* - * 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 org.asynchttpclient.providers.netty.request; -import static org.asynchttpclient.providers.netty.util.HttpUtil.WEBSOCKET; -import static org.asynchttpclient.providers.netty.util.HttpUtil.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; +import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; +import static org.asynchttpclient.util.AsyncHttpProviderUtils.requestTimeout; +import static org.asynchttpclient.util.ProxyUtils.avoidProxy; +import static org.asynchttpclient.util.ProxyUtils.getProxyServer; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; + +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; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.AsyncHandlerExtensions; @@ -31,133 +49,150 @@ import org.asynchttpclient.filter.IOExceptionFilter; import org.asynchttpclient.listener.TransferCompletionHandler; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.timeout.ReadTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.providers.netty.request.timeout.TimeoutsHolder; import org.asynchttpclient.uri.UriComponents; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.ProxyUtils; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.util.Timeout; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; - -public class NettyRequestSender { +public final class NettyRequestSender { private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); - private final AtomicBoolean closed; private final AsyncHttpClientConfig config; - private final Channels channels; + private final ChannelManager channelManager; + private final Timer nettyTimer; + private final AtomicBoolean closed; private final NettyRequestFactory requestFactory; - public NettyRequestSender(AtomicBoolean closed,// - AsyncHttpClientConfig config,// + public NettyRequestSender(AsyncHttpClientConfig config,// NettyAsyncHttpProviderConfig nettyConfig,// - Channels channels) { - this.closed = closed; + ChannelManager channelManager,// + Timer nettyTimer,// + AtomicBoolean closed) { this.config = config; - this.channels = channels; + this.channelManager = channelManager; + this.nettyTimer = nettyTimer; + this.closed = closed; requestFactory = new NettyRequestFactory(config, nettyConfig); } - public boolean retry(NettyResponseFuture future, Channel channel) { + public ListenableFuture sendRequest(final Request request,// + final AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache) throws IOException { if (closed.get()) - return false; + throw new IOException("Closed"); - channels.removeAll(channel); + UriComponents uri = request.getURI(); - if (future == null) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; - } + // 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"); - if (future != null && future.canBeReplayed()) { - future.setState(NettyResponseFuture.STATE.RECONNECTED); - future.getAndSetStatusReceived(false); + ProxyServer proxyServer = getProxyServer(config, request); + boolean resultOfAConnect = future != null && future.getNettyRequest() != null && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; + boolean useProxy = proxyServer != null && !resultOfAConnect; - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } + 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); + } - try { - sendNextRequest(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; - } + /** + * 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); } - public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) - throws IOException { + /** + * 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 { - boolean replayed = false; + 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); - 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) { - channels.abort(future, efe); - } + 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; } - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - replayed = true; - } - return replayed; + newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, true); + return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); } - public void sendNextRequest(final Request request, final NettyResponseFuture f) throws IOException { - sendRequest(request, f.getAsyncHandler(), f, true); - } + private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture originalFuture, + UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { - // FIXME is this useful? Can't we do that when building the request? - private final boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { - return request.getMethod().equals(HttpMethod.GET.name()) && asyncHandler instanceof WebSocketUpgradeHandler; + NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); + + if (originalFuture == null) { + return newNettyResponseFuture(uri, request, asyncHandler, nettyRequest, proxy); + } else { + originalFuture.setNettyRequest(nettyRequest); + originalFuture.setRequest(request); + return originalFuture; + } } private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, ProxyServer proxyServer) { - if (future != null && future.reuseChannel() && isChannelValid(future.channel())) + if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) return future.channel(); else - return channels.pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); + return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); } - private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, - NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { + private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, NettyResponseFuture future, + AsyncHandler asyncHandler, Channel channel) throws IOException { future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); @@ -186,26 +221,6 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur return future; } - private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { - if (request.getInetAddress() != null) - return new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); - - else if (!useProxy || ProxyUtils.avoidProxy(proxy, uri.getHost())) - return new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); - - else - return new InetSocketAddress(proxy.getHost(), proxy.getPort()); - } - - private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { - InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); - - if (request.getLocalAddress() != null) - return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); - else - return bootstrap.connect(remoteAddress); - } - private ListenableFuture sendRequestWithNewChannel(// Request request,// UriComponents uri,// @@ -217,43 +232,43 @@ private ListenableFuture sendRequestWithNewChannel(// boolean useSSl = isSecure(uri) && !useProxy; - // Do not throw an exception when we need an extra connection for a redirect + // 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? - Bootstrap bootstrap = channels.getBootstrap(request.getURI(), useSSl, useProxy); - + Bootstrap bootstrap = channelManager.getBootstrap(request.getURI(), useProxy, useSSl); boolean channelPreempted = false; String poolKey = null; - - // Do not throw an exception when we need an extra connection for a redirect. + + // 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 = channels.getPoolKey(future); + poolKey = channelManager.getPoolKey(future); - channelPreempted = channels.preemptChannel(asyncHandler, poolKey); + channelPreempted = preemptChannel(asyncHandler, poolKey); } try { ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); - channelFuture.addListener(new NettyConnectListener(config, this, future, channels, channelPreempted, poolKey)); + channelFuture.addListener(new NettyConnectListener(config, future, this, channelManager, channelPreempted, poolKey)); } catch (Throwable t) { if (channelPreempted) - channels.abortChannelPreemption(poolKey); + channelManager.abortChannelPreemption(poolKey); - channels.abort(future, t.getCause() == null ? t : t.getCause()); + abort(future, t.getCause() == null ? t : t.getCause()); } return future; } - private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, - NettyRequest nettyRequest, ProxyServer proxyServer) { + private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { - NettyResponseFuture f = new NettyResponseFuture(// + NettyResponseFuture future = new NettyResponseFuture(// uri,// request,// asyncHandler,// @@ -263,110 +278,76 @@ private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Req proxyServer); String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); - if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { - f.setDontWriteBodyBecauseExpectContinue(true); - } - return f; + if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) + future.setDontWriteBodyBecauseExpectContinue(true); + return future; } - private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, - NettyResponseFuture originalFuture, UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { - - NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); + 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; - if (originalFuture == null) { - return newNettyResponseFuture(uri, request, asyncHandler, nettyRequest, proxy); - } else { - originalFuture.setNettyRequest(nettyRequest); - originalFuture.setRequest(request); - return originalFuture; - } - } + NettyRequest nettyRequest = future.getNettyRequest(); + HttpRequest httpRequest = nettyRequest.getHttpRequest(); + AsyncHandler handler = future.getAsyncHandler(); - private boolean isChannelValid(Channel channel) { - return channel != null && channel.isOpen() && channel.isActive(); - } + if (handler instanceof TransferCompletionHandler) + configureTransferAdapter(handler, httpRequest); - private ListenableFuture sendRequestThroughSslProxy(// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache,// - UriComponents uri,// - ProxyServer proxyServer) throws IOException { + if (!future.isHeadersAlreadyWrittenOnContinue()) { + try { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - // Using CONNECT depends on wither we can fetch a valid channel or not + channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); + } catch (Throwable cause) { + // FIXME why not notify? + LOGGER.debug(cause.getMessage(), cause); + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + return; + } + } - // Loop until we get a valid channel from the pool and it's still valid once the request is built - NettyResponseFuture newFuture = null; - for (int i = 0; i < 3; i++) { - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); - if (isChannelValid(channel)) { - if (newFuture == null) - newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); + if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) && nettyRequest.getBody() != null) + nettyRequest.getBody().write(channel, future, config); - if (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; + } catch (Throwable ioe) { + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } } - newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, true); - return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); + scheduleTimeouts(future); } - private ListenableFuture sendRequestWithCertainForceConnect(// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache,// - UriComponents uri,// - ProxyServer proxyServer,// - boolean useProxy,// - boolean forceConnect) throws IOException { - // 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 - NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); + private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { + if (request.getInetAddress() != null) + return new InetSocketAddress(request.getInetAddress(), getDefaultPort(uri)); - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + else if (!useProxy || avoidProxy(proxy, uri.getHost())) + return new InetSocketAddress(uri.getHost(), getDefaultPort(uri)); - if (isChannelValid(channel)) - return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); else - return sendRequestWithNewChannel(request, uri, proxyServer, useProxy, newFuture, asyncHandler, reclaimCache); + return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - public ListenableFuture sendRequest(final Request request,// - final AsyncHandler asyncHandler,// - NettyResponseFuture future,// - boolean reclaimCache) throws IOException { - - if (closed.get()) { - throw new IOException("Closed"); - } - - // FIXME really useful? Why not do this check when building the request? - if (request.getURI().getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { - throw new IOException("WebSocket method must be a GET"); - } - - UriComponents uri = request.getURI(); - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - boolean resultOfAConnect = future != null && future.getNettyRequest() != null - && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; - boolean useProxy = proxyServer != null && !resultOfAConnect; + private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, Bootstrap bootstrap) { + InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); - 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); + if (request.getLocalAddress() != null) + return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); + else + return bootstrap.connect(remoteAddress); } private void configureTransferAdapter(AsyncHandler handler, HttpRequest httpRequest) { @@ -382,88 +363,163 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { try { nettyResponseFuture.touch(); - int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, nettyResponseFuture.getRequest()); + int requestTimeoutInMs = requestTimeout(config, nettyResponseFuture.getRequest()); TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { - Timeout requestTimeout = channels.newTimeoutInMs(new RequestTimeoutTimerTask(nettyResponseFuture, channels, timeoutsHolder, - closed, requestTimeoutInMs), requestTimeoutInMs); + 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 = channels.newTimeoutInMs(new ReadTimeoutTimerTask(nettyResponseFuture, channels, - timeoutsHolder, closed, requestTimeoutInMs, readTimeout), readTimeout); + // 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) { - channels.abort(nettyResponseFuture, ex); + abort(nettyResponseFuture, ex); } } - public final 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 (!channel.isOpen() || !channel.isActive()) { - return; + 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(); + if (channel != null) + channelManager.closeChannel(channel); + + if (!future.isDone()) { + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); + } + + future.abort(t); + } + + public boolean retry(NettyResponseFuture future, Channel channel) { + + if (isClosed()) + return false; + + channelManager.removeAll(channel); + + if (future == null) { + Object attachment = Channels.getDefaultAttribute(channel); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; + } + + if (future != null && future.canBeReplayed()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); + future.getAndSetStatusReceived(false); + + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } - NettyRequest nettyRequest = future.getNettyRequest(); - HttpRequest httpRequest = nettyRequest.getHttpRequest(); - AsyncHandler handler = future.getAsyncHandler(); + try { + sendNextRequest(future.getRequest(), future); + return true; - if (handler instanceof TransferCompletionHandler) { - configureTransferAdapter(handler, httpRequest); + } 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; + } + } - if (!future.isHeadersAlreadyWrittenOnContinue()) { - try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - } - channel.writeAndFlush(httpRequest, channel.newProgressivePromise()).addListener( - new ProgressListener(config, future.getAsyncHandler(), future, true, 0L)); - } catch (Throwable cause) { - // FIXME why not notify? - LOGGER.debug(cause.getMessage(), cause); - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; + 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 (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) - && nettyRequest.getBody() != null) - nettyRequest.getBody().write(channel, future, config); + 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); + } + + // FIXME is this useful? Can't we do that when building the request? + private boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { + return request.getMethod().equals(HttpMethod.GET.name()) && asyncHandler instanceof WebSocketUpgradeHandler; + } + + private 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); - } catch (Throwable ioe) { try { - channel.close(); - } catch (RuntimeException ex) { + channelManager.verifyChannelPipeline(channel.pipeline(), uri.getScheme()); + } catch (Exception ex) { LOGGER.debug(ex.getMessage(), ex); } } + return channel; + } - scheduleTimeouts(future); + private 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 { + 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); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } - channels.drainChannel(channel, future); + + channelManager.drainChannel(channel, future); sendNextRequest(newRequest, future); } + + public boolean isClosed() { + return closed.get(); + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java old mode 100644 new mode 100755 index 78c9f35919..8e1b7fe2cd --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/ProgressListener.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 org.asynchttpclient.providers.netty.request; @@ -41,8 +39,11 @@ public class ProgressListener implements ChannelProgressiveFutureListener { private final long expectedTotal; private long lastProgress = 0L; - public ProgressListener(AsyncHttpClientConfig config, AsyncHandler asyncHandler, NettyResponseFuture future, - boolean notifyHeaders, long expectedTotal) { + public ProgressListener(AsyncHttpClientConfig config,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean notifyHeaders,// + long expectedTotal) { this.config = config; this.asyncHandler = asyncHandler; this.future = future; @@ -83,7 +84,8 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { @Override public void operationComplete(ChannelProgressiveFuture cf) { - // The write operation failed. If the channel was cached, it means it got asynchronously closed. + // The write operation failed. If the channel was cached, it means it + // got asynchronously closed. // Let's retry a second time. if (!abortOnThrowable(cf.cause(), cf.channel())) { @@ -91,9 +93,10 @@ public void operationComplete(ChannelProgressiveFuture 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() : config.getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java old mode 100644 new mode 100755 index 271046a3e7..e48d6d8a13 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java old mode 100644 new mode 100755 index 857b610784..49fabeef29 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java old mode 100644 new mode 100755 index 97bdc34701..dbff022523 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/FeedableBodyGenerator.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java old mode 100644 new mode 100755 index c35606d17b..cea79857c3 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBody.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 org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java old mode 100644 new mode 100755 index fb9108e7b1..7dac353e5b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.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 org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java old mode 100644 new mode 100755 index eb2e9e9bfb..953461fb84 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyByteArrayBody.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 org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java old mode 100644 new mode 100755 index 5360943b26..3043bd3e32 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.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 org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java old mode 100644 new mode 100755 index e848c21e39..4412cd9bf4 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.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 org.asynchttpclient.providers.netty.request.body; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java old mode 100644 new mode 100755 index 742ed21657..0c69440533 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyMultipartBody.java @@ -1,34 +1,33 @@ /* - * 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 org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.multipart.MultipartUtils.newMultipartBody; + +import java.util.List; + import org.asynchttpclient.FluentCaseInsensitiveStringsMap; import org.asynchttpclient.multipart.MultipartBody; -import org.asynchttpclient.multipart.MultipartUtils; import org.asynchttpclient.multipart.Part; import org.asynchttpclient.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); + this(newMultipartBody(parts, headers), nettyConfig); } private NettyMultipartBody(MultipartBody body, NettyAsyncHttpProviderConfig nettyConfig) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java old mode 100644 new mode 100755 index 6199c9cd9b..c500bdd369 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -1,28 +1,23 @@ /* - * 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 org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; - import io.netty.util.Timeout; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; public class ReadTimeoutTimerTask extends TimeoutTimerTask { @@ -31,19 +26,18 @@ public class ReadTimeoutTimerTask extends TimeoutTimerTask { public ReadTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// + NettyRequestSender requestSender,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed,// long requestTimeout,// long readTimeout) { - super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + super(nettyResponseFuture, requestSender, timeoutsHolder); this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } @Override public void run(Timeout timeout) throws Exception { - if (clientClosed.get()) { + if (requestSender.isClosed()) { timeoutsHolder.cancel(); return; } @@ -64,7 +58,7 @@ public void run(Timeout timeout) throws Exception { } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.readTimeout = channels.newTimeoutInMs(this, durationBeforeCurrentReadTimeout); + timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java old mode 100644 new mode 100755 index cb4d2ca509..51c72d1574 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -1,28 +1,23 @@ /* - * 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 org.asynchttpclient.providers.netty.request.timeout; import static org.asynchttpclient.util.DateUtils.millisTime; - -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; - import io.netty.util.Timeout; -import java.util.concurrent.atomic.AtomicBoolean; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; public class RequestTimeoutTimerTask extends TimeoutTimerTask { @@ -30,11 +25,10 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { public RequestTimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// + NettyRequestSender requestSender,// TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed,// long requestTimeout) { - super(nettyResponseFuture, channels, timeoutsHolder, clientClosed); + super(nettyResponseFuture, requestSender, timeoutsHolder); this.requestTimeout = requestTimeout; } @@ -44,9 +38,8 @@ public void run(Timeout timeout) throws Exception { // in any case, cancel possible idleConnectionTimeout timeoutsHolder.cancel(); - if (clientClosed.get()) { + if (requestSender.isClosed()) return; - } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java old mode 100644 new mode 100755 index e599e5d871..b774b7763a --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutTimerTask.java @@ -1,52 +1,46 @@ /* - * 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 org.asynchttpclient.providers.netty.request.timeout; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.util.TimerTask; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; + +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.NettyRequestSender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); protected final NettyResponseFuture nettyResponseFuture; - protected final Channels channels; + protected final NettyRequestSender requestSender; protected final TimeoutsHolder timeoutsHolder; - protected final AtomicBoolean clientClosed; public TimeoutTimerTask(// NettyResponseFuture nettyResponseFuture,// - Channels channels,// - TimeoutsHolder timeoutsHolder,// - AtomicBoolean clientClosed) { + NettyRequestSender requestSender,// + TimeoutsHolder timeoutsHolder) { this.nettyResponseFuture = nettyResponseFuture; - this.channels = channels; + this.requestSender = requestSender; this.timeoutsHolder = timeoutsHolder; - this.clientClosed = clientClosed; } protected void expire(String message, long ms) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, ms); - channels.abort(nettyResponseFuture, new TimeoutException(message)); + requestSender.abort(nettyResponseFuture, new TimeoutException(message)); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java old mode 100644 new mode 100755 index d032672a4a..9e6f1cb22f --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/TimeoutsHolder.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 org.asynchttpclient.providers.netty.request.timeout; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java old mode 100644 new mode 100755 index aad1f2e5af..afccb511ee --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.providers.netty.response; -import org.asynchttpclient.providers.netty.util.ByteBufUtil; +import static org.asynchttpclient.providers.netty.util.ByteBufUtils.*; import io.netty.buffer.ByteBuf; @@ -32,7 +32,7 @@ public class EagerResponseBodyPart extends NettyResponseBodyPart { public EagerResponseBodyPart(ByteBuf buf, boolean last) { super(last); - bytes = ByteBufUtil.byteBuf2Bytes(buf); + bytes = byteBuf2Bytes(buf); } /** diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java old mode 100644 new mode 100755 diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java old mode 100644 new mode 100755 index 94eb15d70d..17d593541e --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponse.java @@ -1,30 +1,20 @@ /* - * 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 org.asynchttpclient.providers.netty.response; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.HttpResponseHeaders; -import org.asynchttpclient.HttpResponseStatus; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.cookie.CookieDecoder; -import org.asynchttpclient.date.TimeConverter; -import org.asynchttpclient.providers.ResponseBase; -import org.asynchttpclient.util.AsyncHttpProviderUtils; -import org.asynchttpclient.util.MiscUtils; - +import static org.asynchttpclient.util.AsyncHttpProviderUtils.contentToBytes; +import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import io.netty.handler.codec.http.HttpHeaders; import java.io.ByteArrayInputStream; @@ -35,6 +25,14 @@ import java.util.Collections; import java.util.List; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.HttpResponseHeaders; +import org.asynchttpclient.HttpResponseStatus; +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.cookie.CookieDecoder; +import org.asynchttpclient.date.TimeConverter; +import org.asynchttpclient.providers.ResponseBase; + /** * Wrapper around the {@link org.asynchttpclient.Response} API. */ @@ -58,7 +56,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { // should be fine; except that it may split multi-byte chars (last char may become '?') charset = calculateCharset(charset); - byte[] b = AsyncHttpProviderUtils.contentToBytes(bodyParts, maxLength); + byte[] b = contentToBytes(bodyParts, maxLength); return new String(b, charset); } @@ -66,11 +64,11 @@ protected List buildCookies() { List setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE2); - if (!MiscUtils.isNonEmpty(setCookieHeaders)) { + if (!isNonEmpty(setCookieHeaders)) { setCookieHeaders = headers.getHeaders().get(HttpHeaders.Names.SET_COOKIE); } - if (MiscUtils.isNonEmpty(setCookieHeaders)) { + if (isNonEmpty(setCookieHeaders)) { List cookies = new ArrayList(); for (String value : setCookieHeaders) { Cookie c = CookieDecoder.decode(value, timeConverter); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java old mode 100644 new mode 100755 index 2c50ce6a79..76399a14e6 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseBodyPart.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 org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java old mode 100644 new mode 100755 index 5f9f56da92..a40068965f --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.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 org.asynchttpclient.providers.netty.response; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java old mode 100644 new mode 100755 index 996038de10..1c74721d23 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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 org.asynchttpclient.providers.netty.response; @@ -34,7 +31,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(UriComponents uri, HttpResponse response, AsyncHttpClientConfig config) { + public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { super(uri, config); this.response = response; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java old mode 100644 new mode 100755 similarity index 96% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java index 9c6bb8d7a7..f370ac153b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/ByteBufUtils.java @@ -19,11 +19,11 @@ import java.util.List; -public final class ByteBufUtil { +public final class ByteBufUtils { public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - private ByteBufUtil() { + private ByteBufUtils() { } public static byte[] byteBuf2Bytes(ByteBuf buf) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java old mode 100644 new mode 100755 similarity index 96% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index 906bc7e8eb..b7ab94e3fc --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -18,14 +18,14 @@ import org.asynchttpclient.uri.UriComponents; -public final class HttpUtil { +public final class HttpUtils { public static final String HTTPS = "https"; public static final String HTTP = "http"; 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java old mode 100644 new mode 100755 index e9c32e6f28..2a87ac293b --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtils.java old mode 100644 new mode 100755 similarity index 91% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtils.java index 4097ab31d6..c308edaea4 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/WebSocketUtil.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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 @@ -19,7 +20,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"; From 5ee604e48ed96f306cbea6fc4dfd83702fe8553b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 10:59:37 +0200 Subject: [PATCH 0164/2070] Would would write schemes not in lowercase? --- .../org/asynchttpclient/providers/netty/util/HttpUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index b7ab94e3fc..e13b7ee51b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -33,11 +33,11 @@ public static boolean isNTLM(List auth) { } public static boolean isWebSocket(String scheme) { - return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return WEBSOCKET.equals(scheme) || WEBSOCKET_SSL.equals(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 743e728f885ac0413e1a246c4f7e46828db4ae68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 11:28:24 +0200 Subject: [PATCH 0165/2070] Rename DefaultAttribute into Attribute --- .../netty/channel/ChannelManager.java | 35 ++++++++++++------- .../providers/netty/channel/Channels.java | 11 ++---- .../channel/pool/DefaultChannelPool.java | 6 ++-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../providers/netty/handler/Processor.java | 20 +++++------ .../providers/netty/handler/Protocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 4 +-- .../netty/request/NettyConnectListener.java | 4 +-- .../netty/request/NettyRequestSender.java | 8 ++--- 9 files changed, 48 insertions(+), 44 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 047dfc2a26..647ced78fe 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -293,9 +293,9 @@ public void close() { openChannels.close(); for (Channel channel : openChannels) { - Object attachment = Channels.getDefaultAttribute(channel); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; future.cancelTimeouts(); } } @@ -362,16 +362,24 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep return sslHandler; } + 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 @@ -392,13 +400,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 Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSSl) { @@ -421,6 +430,6 @@ public void call() throws Exception { } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setDefaultAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java index eda10d57d9..a193ae5f01 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/Channels.java @@ -14,7 +14,6 @@ package org.asynchttpclient.providers.netty.channel; import io.netty.channel.Channel; -import io.netty.handler.ssl.SslHandler; import io.netty.util.Attribute; import io.netty.util.AttributeKey; @@ -24,21 +23,17 @@ public class Channels { private static final AttributeKey DEFAULT_ATTRIBUTE = AttributeKey.valueOf("default"); - public static SslHandler getSslHandler(Channel channel) { - return channel.pipeline().get(SslHandler.class); - } - - public static Object getDefaultAttribute(Channel channel) { + public static Object getAttribute(Channel channel) { Attribute attr = channel.attr(DEFAULT_ATTRIBUTE); return attr != null ? attr.get() : null; } - public static void setDefaultAttribute(Channel channel, Object o) { + public static void setAttribute(Channel channel, Object o) { channel.attr(DEFAULT_ATTRIBUTE).set(o); } public static void setDiscard(Channel channel) { - setDefaultAttribute(channel, DiscardEvent.INSTANCE); + setAttribute(channel, DiscardEvent.INSTANCE); } public static boolean isChannelValid(Channel channel) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java index 3a04157660..c5cbbaad49 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/pool/DefaultChannelPool.java @@ -150,9 +150,9 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - Object attachment = Channels.getDefaultAttribute(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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 380121278c..17d739f515 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -239,7 +239,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.setDefaultAttribute(channel, callback); + Channels.setAttribute(channel, callback); else callback.call(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java index 8cbd848de6..87a1a357df 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Processor.java @@ -64,12 +64,12 @@ public Processor(AsyncHttpClientConfig config,// public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { Channel channel = ctx.channel(); - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (attribute instanceof Callback && msg instanceof LastHttpContent) { Callback ac = (Callback) attribute; ac.call(); - Channels.setDefaultAttribute(channel, DiscardEvent.INSTANCE); + Channels.setAttribute(channel, DiscardEvent.INSTANCE); } else if (attribute instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attribute; @@ -98,16 +98,16 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { LOGGER.trace("super.channelClosed", ex); } - Object attachment = Channels.getDefaultAttribute(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.setDefaultAttribute(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.class.cast(attachment); + } else if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = NettyResponseFuture.class.cast(attribute); future.touch(); if (!config.getIOExceptionFilters().isEmpty() && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) @@ -136,7 +136,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Excep LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); try { - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (attribute instanceof NettyResponseFuture) { future = (NettyResponseFuture) attribute; future.attachChannel(null, false); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java index 8eb8363a47..cffa03e2da 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/Protocol.java @@ -144,7 +144,7 @@ protected boolean exitAfterHandlingRedirect(// // We must make sure there is no bytes left before // executing the next request. // FIXME investigate this - Channels.setDefaultAttribute(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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 8859822341..ba1ad04b02 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -164,7 +164,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr @Override public void onError(Channel channel, Throwable e) { try { - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); logger.warn("onError {}", e); if (!(attribute instanceof NettyResponseFuture)) { return; @@ -186,7 +186,7 @@ public void onError(Channel channel, Throwable e) { @Override public void onClose(Channel channel) { logger.trace("onClose {}"); - Object attribute = Channels.getDefaultAttribute(channel); + Object attribute = Channels.getAttribute(channel); if (!(attribute instanceof NettyResponseFuture)) return; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b4254bc088..6268c6acc8 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -85,9 +85,9 @@ private void writeRequest(Channel channel) { } public void onFutureSuccess(final Channel channel) throws ConnectException { - Channels.setDefaultAttribute(channel, future); + Channels.setAttribute(channel, future); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); - final SslHandler sslHandler = Channels.getSslHandler(channel); + final SslHandler sslHandler = channelManager.getSslHandler(channel.pipeline()); if (hostnameVerifier != null && sslHandler != null) { final String host = future.getURI().getHost(); sslHandler.handshakeFuture().addListener(new GenericFutureListener>() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 5dd4ee7674..9d4d2e54d0 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -198,7 +198,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.setDefaultAttribute(channel, future); + Channels.setAttribute(channel, future); try { writeRequest(future, channel); @@ -409,9 +409,9 @@ public boolean retry(NettyResponseFuture future, Channel channel) { channelManager.removeAll(channel); if (future == null) { - Object attachment = Channels.getDefaultAttribute(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()) { From e57085973be212c20dc5af95c5aa2e9fc49790c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:16:40 +0200 Subject: [PATCH 0166/2070] clean up --- .../org/asynchttpclient/SSLEngineFactory.java | 20 +++++------ .../netty/NettyAsyncHttpProviderConfig.java | 35 ++++++++++++------- .../netty/channel/ChannelManager.java | 4 +-- .../netty/request/body/NettyBodyBody.java | 9 ++--- .../netty/request/body/NettyFileBody.java | 26 +++++++------- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java index 0289a0e109..a7152bbb4a 100644 --- a/api/src/main/java/org/asynchttpclient/SSLEngineFactory.java +++ b/api/src/main/java/org/asynchttpclient/SSLEngineFactory.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 org.asynchttpclient; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index f066ab51d5..9c1c6ed330 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -31,7 +31,8 @@ import java.util.Set; /** - * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. + * This class can be used to pass Netty's internal configuration options. See + * Netty documentation for more information. */ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig, Object> { @@ -41,8 +42,10 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig name, Object value) { @@ -122,24 +125,19 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private AdditionalChannelInitializer wssAdditionalChannelInitializer; /** - * HttpClientCodec's maxInitialLineLength + * Allow configuring Netty's HttpClientCodecs. */ private int httpClientCodecMaxInitialLineLength = 4096; - - /** - * HttpClientCodec's maxHeaderSize - */ private int httpClientCodecMaxHeaderSize = 8192; - - /** - * HttpClientCodec's maxChunkSize - */ private int httpClientCodecMaxChunkSize = 8192; private ResponseBodyPartFactory bodyPartFactory = new EagerResponseBodyPartFactory(); private ChannelPool channelPool; + /** + * Allow one to disable zero copy for bodies and use chunking instead + */ private boolean disableZeroCopy; private Timer nettyTimer; @@ -148,6 +146,11 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private SSLEngineFactory sslEngineFactory; + /** + * chunkedFileChunkSize + */ + private int chunkedFileChunkSize = 8192; + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -259,4 +262,12 @@ public SSLEngineFactory getSslEngineFactory() { public void setSslEngineFactory(SSLEngineFactory sslEngineFactory) { this.sslEngineFactory = sslEngineFactory; } + + public int getChunkedFileChunkSize() { + return chunkedFileChunkSize; + } + + public void setChunkedFileChunkSize(int chunkedFileChunkSize) { + this.chunkedFileChunkSize = chunkedFileChunkSize; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 647ced78fe..bca5bdd1c1 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -362,11 +362,11 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep return sslHandler; } - 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 7dac353e5b..43c39cfea7 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -18,6 +18,7 @@ import org.asynchttpclient.BodyGenerator; import org.asynchttpclient.RandomAccessBody; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; @@ -38,11 +39,11 @@ public class NettyBodyBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); private final Body body; - private final boolean disableZeroCopy; + private final NettyAsyncHttpProviderConfig nettyConfig; public NettyBodyBody(Body body, NettyAsyncHttpProviderConfig nettyConfig) { this.body = body; - disableZeroCopy = nettyConfig.isDisableZeroCopy(); + this.nettyConfig = nettyConfig; } public Body getBody() { @@ -61,9 +62,9 @@ public String getContentType() { @Override public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { - Object msg; - if (Channels.getSslHandler(channel) == null && body instanceof RandomAccessBody && !disableZeroCopy) { + Object msg; + if (!ChannelManager.isSslHandlerConfigured(channel.pipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { msg = new BodyFileRegion((RandomAccessBody) body); } else { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java index 3043bd3e32..7b5234e5cd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -13,14 +13,6 @@ */ package org.asynchttpclient.providers.netty.request.body; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; -import org.asynchttpclient.providers.netty.channel.Channels; -import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelProgressiveFuture; @@ -33,16 +25,22 @@ import java.io.IOException; import java.io.RandomAccessFile; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; +import org.asynchttpclient.providers.netty.channel.ChannelManager; +import org.asynchttpclient.providers.netty.future.NettyResponseFuture; +import org.asynchttpclient.providers.netty.request.ProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + 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 boolean disableZeroCopy; + private final NettyAsyncHttpProviderConfig nettyConfig; public NettyFileBody(File file, NettyAsyncHttpProviderConfig nettyConfig) throws IOException { this(file, 0, file.length(), nettyConfig); @@ -55,7 +53,7 @@ public NettyFileBody(File file, long offset, long length, NettyAsyncHttpProvider this.file = file; this.offset = offset; this.length = length; - disableZeroCopy = nettyConfig.isDisableZeroCopy(); + this.nettyConfig = nettyConfig; } public File getFile() { @@ -82,8 +80,8 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien try { ChannelFuture writeFuture; - if (Channels.getSslHandler(channel) != null || disableZeroCopy) { - writeFuture = channel.write(new ChunkedFile(raf, offset, length, MAX_BUFFERED_BYTES), channel.newProgressivePromise()); + if (ChannelManager.isSslHandlerConfigured(channel.pipeline()) || nettyConfig.isDisableZeroCopy()) { + writeFuture = channel.write(new ChunkedFile(raf, offset, length, nettyConfig.getChunkedFileChunkSize()), channel.newProgressivePromise()); } else { FileRegion region = new DefaultFileRegion(raf.getChannel(), offset, length); writeFuture = channel.write(region, channel.newProgressivePromise()); From 92023dabaacceee52c56d1702bec45fe11aad664 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:37:01 +0200 Subject: [PATCH 0167/2070] Make transferEncoding configurable, fix FilePart constructors, close #647 --- .../multipart/AbstractFilePart.java | 9 ++++--- .../multipart/ByteArrayPart.java | 11 +++++--- .../asynchttpclient/multipart/FilePart.java | 27 ++++++++++--------- .../asynchttpclient/multipart/PartBase.java | 6 ++--- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index a4d5f4e9b9..8e711d3a98 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/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 transfertEncoding) { + super(name,// + contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// + charset,// + contentId,// + transfertEncoding == null ? DEFAULT_TRANSFER_ENCODING : transfertEncoding); } protected void visitDispositionHeader(PartVisitor visitor) throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index a7cd65337e..bc4660cb8e 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index ed4cb93f09..3ea77ed562 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 2d9d274705..6273fce8ed 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java @@ -55,15 +55,15 @@ public abstract class PartBase implements 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 * @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 { From 2a57096f0dc86d65028cf6ed5a19c454c81f5b68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:14:19 +0200 Subject: [PATCH 0168/2070] Drop useless broken test --- .../async/AsyncStreamHandlerTest.java | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java index 835bdf31be..4bd4d6fe6a 100644 --- a/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncStreamHandlerTest.java @@ -327,47 +327,6 @@ public String onCompleted() throws Exception { } } - @Test(groups = { "online", "default_provider" }) - public void asyncStream302WithBody() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); - final AtomicReference statusCode = new AtomicReference(0); - final AtomicReference headers = new AtomicReference(); - try { - 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 { - 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 { - c.close(); - } - } - @Test(groups = { "online", "default_provider" }) public void asyncStream302RedirectWithBody() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); From 98b66cbdd1594dbb61f2d1479f87e2eda35fd755 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:18:36 +0200 Subject: [PATCH 0169/2070] Fix RemoteSiteTest.testGoogleComWithTimeout, redirect depends on geoloc --- api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java index f5b46b21fb..7e8ad5f21c 100644 --- a/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java +++ b/api/src/test/java/org/asynchttpclient/async/RemoteSiteTest.java @@ -119,7 +119,7 @@ public void testGoogleComWithTimeout() throws Exception { try { Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); - assertEquals(response.getStatusCode(), 302); + assertTrue(response.getStatusCode() == 301 || response.getStatusCode() == 302); } finally { c.close(); } From 06a727f9f435bc5a7cac1efcca060bcd59605ec5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 08:53:43 +0200 Subject: [PATCH 0170/2070] Rename handshakeTimeoutInMillis into handshakeTimeout --- .../providers/netty/NettyAsyncHttpProviderConfig.java | 2 +- .../providers/netty/channel/ChannelManager.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 9c1c6ed330..185d7ea275 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -247,7 +247,7 @@ public void setNettyTimer(Timer nettyTimer) { this.nettyTimer = nettyTimer; } - public long getHandshakeTimeoutInMillis() { + public long getHandshakeTimeout() { return handshakeTimeoutInMillis; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index bca5bdd1c1..6fb3b03f3b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -83,7 +83,7 @@ public class ChannelManager { private final Bootstrap webSocketBootstrap; private final Bootstrap secureWebSocketBootstrap; - private final long handshakeTimeoutInMillis; + private final long handshakeTimeout; private final ChannelPool channelPool; private final boolean maxConnectionsEnabled; @@ -144,7 +144,7 @@ public boolean remove(Object o) { channel2KeyPool = null; } - handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + handshakeTimeout = nettyConfig.getHandshakeTimeout(); // check if external EventLoopGroup is defined allowReleaseEventLoopGroup = nettyConfig.getEventLoopGroup() == null; @@ -356,8 +356,8 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws IOExcep } SslHandler sslHandler = new SslHandler(sslEngine); - if (handshakeTimeoutInMillis > 0) - sslHandler.setHandshakeTimeoutMillis(handshakeTimeoutInMillis); + if (handshakeTimeout > 0) + sslHandler.setHandshakeTimeoutMillis(handshakeTimeout); return sslHandler; } From a48e469214b450a38bc3734a240d6e9f01560199 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 09:48:18 +0200 Subject: [PATCH 0171/2070] Rename Netty response elements --- .../netty/NettyAsyncHttpProviderConfig.java | 8 ++++---- .../providers/netty/handler/HttpProtocol.java | 14 +++++++------- .../providers/netty/handler/WebSocketProtocol.java | 10 +++++----- ...dyPart.java => EagerNettyResponseBodyPart.java} | 4 ++-- ...odyPart.java => LazyNettyResponseBodyPart.java} | 4 ++-- ...ponseHeaders.java => NettyResponseHeaders.java} | 6 +++--- ...esponseStatus.java => NettyResponseStatus.java} | 4 ++-- .../providers/netty/NettyAsyncResponseTest.java | 8 ++++---- 8 files changed, 29 insertions(+), 29 deletions(-) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{EagerResponseBodyPart.java => EagerNettyResponseBodyPart.java} (93%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{LazyResponseBodyPart.java => LazyNettyResponseBodyPart.java} (93%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{ResponseHeaders.java => NettyResponseHeaders.java} (90%) rename providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/{ResponseStatus.java => NettyResponseStatus.java} (93%) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 185d7ea275..36659292ad 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -16,8 +16,8 @@ import org.asynchttpclient.AsyncHttpProviderConfig; import org.asynchttpclient.SSLEngineFactory; import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; -import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import io.netty.buffer.ByteBuf; @@ -102,7 +102,7 @@ public static class EagerResponseBodyPartFactory implements ResponseBodyPartFact @Override public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new EagerResponseBodyPart(buf, last); + return new EagerNettyResponseBodyPart(buf, last); } } @@ -110,7 +110,7 @@ public static class LazyResponseBodyPartFactory implements ResponseBodyPartFacto @Override public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { - return new LazyResponseBodyPart(buf, last); + return new LazyNettyResponseBodyPart(buf, last); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 17d739f515..98be1659cb 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -50,8 +50,8 @@ import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.ResponseHeaders; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.spnego.SpnegoEngine; import org.asynchttpclient.uri.UriComponents; @@ -345,7 +345,7 @@ private boolean exitAfterHandlingConnect(// return false; } - private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseStatus status) + private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, NettyResponseStatus status) throws IOException, Exception { if (!future.getAndSetStatusReceived(true) && handler.onStatusReceived(status) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); @@ -354,7 +354,7 @@ private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture return false; } - private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, ResponseHeaders responseHeaders) + private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, NettyResponseHeaders responseHeaders) throws IOException, Exception { if (!response.headers().isEmpty() && handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); @@ -375,11 +375,11 @@ private boolean handleHttpResponse(final HttpResponse response, final Channel ch 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().code(); 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) || // @@ -428,7 +428,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f LastHttpContent lastChunk = (LastHttpContent) chunk; HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); if (!trailingHeaders.isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), trailingHeaders); + NettyResponseHeaders responseHeaders = new NettyResponseHeaders(future.getHttpHeaders(), trailingHeaders); interrupt = handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE; } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index ba1ad04b02..e8e0917338 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -39,8 +39,8 @@ import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.ResponseHeaders; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; @@ -73,8 +73,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; @@ -93,7 +93,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) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java index afccb511ee..e993bd4975 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/EagerNettyResponseBodyPart.java @@ -26,11 +26,11 @@ * A callback class used when an HTTP response body is received. * Bytes are eagerly fetched from the ByteBuf */ -public class EagerResponseBodyPart extends NettyResponseBodyPart { +public class EagerNettyResponseBodyPart extends NettyResponseBodyPart { private final byte[] bytes; - public EagerResponseBodyPart(ByteBuf buf, boolean last) { + public EagerNettyResponseBodyPart(ByteBuf buf, boolean last) { super(last); bytes = byteBuf2Bytes(buf); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java index 31091bd605..d3f136b9f1 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyResponseBodyPart.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/LazyNettyResponseBodyPart.java @@ -22,13 +22,13 @@ /** * A callback class used when an HTTP response body is received. */ -public class LazyResponseBodyPart extends NettyResponseBodyPart { +public class LazyNettyResponseBodyPart extends NettyResponseBodyPart { private static final String ERROR_MESSAGE = "This implementation is intended for one to directly read from the underlying ByteBuf and release after usage. Not for the fainted heart!"; private final ByteBuf buf; - public LazyResponseBodyPart(ByteBuf buf, boolean last) { + public LazyNettyResponseBodyPart(ByteBuf buf, boolean last) { super(last); this.buf = buf; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseHeaders.java similarity index 90% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseHeaders.java index a40068965f..375f0cd3bf 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseHeaders.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseStatus.java similarity index 93% rename from providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java rename to providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/NettyResponseStatus.java index 1c74721d23..f869f35d1a 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/response/ResponseStatus.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java index f35b77dafb..9158571853 100644 --- a/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java +++ b/providers/netty/src/test/java/org/asynchttpclient/providers/netty/NettyAsyncResponseTest.java @@ -19,7 +19,7 @@ import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.cookie.Cookie; import org.asynchttpclient.providers.netty.response.NettyResponse; -import org.asynchttpclient.providers.netty.response.ResponseStatus; +import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.testng.annotations.Test; import java.text.SimpleDateFormat; @@ -42,7 +42,7 @@ public void testCookieParseExpires() { Date date = new Date(System.currentTimeMillis() + 60000); 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() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -60,7 +60,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() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -76,7 +76,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() { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders() { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); From e19c611843dc12b2702045896e4c992dba78e6ca Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 10:01:05 +0200 Subject: [PATCH 0172/2070] Fix log --- .../providers/netty/request/NettyConnectListener.java | 1 - .../providers/netty/request/NettyRequestSender.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index 6268c6acc8..b463d70d55 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -126,7 +126,6 @@ public void onFutureFailure(Channel channel, Throwable cause) { && cause != null// && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - LOGGER.debug("Retrying {} ", future.getNettyRequest()); if (requestSender.retry(future, channel)) { return; } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 9d4d2e54d0..207d0596e6 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -418,7 +418,7 @@ public boolean retry(NettyResponseFuture future, Channel channel) { future.setState(NettyResponseFuture.STATE.RECONNECTED); future.getAndSetStatusReceived(false); - 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(); } From 41e4c4716cb0876be4b5f97639572be86312a9e2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 14:18:38 +0200 Subject: [PATCH 0173/2070] Make acceptAnyCertificate doesn't disable HostnameVerifier, close #649 --- .../AsyncHttpClientConfig.java | 35 ++++++++++--------- .../AsyncHttpClientConfigBean.java | 1 - .../AsyncHttpClientConfigDefaults.java | 4 --- .../util/AllowAllHostnameVerifier.java | 22 ------------ 4 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 5146b997a6..8f1aefbf30 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -17,15 +17,6 @@ import static org.asynchttpclient.AsyncHttpClientConfigDefaults.*; -import org.asynchttpclient.date.TimeConverter; -import org.asynchttpclient.filter.IOExceptionFilter; -import org.asynchttpclient.filter.RequestFilter; -import org.asynchttpclient.filter.ResponseFilter; -import org.asynchttpclient.util.ProxyUtils; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; - import java.io.IOException; import java.io.InputStream; import java.util.Collections; @@ -35,6 +26,16 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; + +import org.asynchttpclient.date.TimeConverter; +import org.asynchttpclient.filter.IOExceptionFilter; +import org.asynchttpclient.filter.RequestFilter; +import org.asynchttpclient.filter.ResponseFilter; +import org.asynchttpclient.util.DefaultHostnameVerifier; +import org.asynchttpclient.util.ProxyUtils; + /** * Configuration class to use with a {@link AsyncHttpClient}. System property can be also used to configure this * object default behavior by doing: @@ -538,7 +539,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(); @@ -1082,17 +1083,19 @@ public Builder(AsyncHttpClientConfig prototype) { */ public AsyncHttpClientConfig build() { - 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/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index d68c6a8984..150187cea6 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -65,7 +65,6 @@ void configureDefaults() { disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); - hostnameVerifier = defaultHostnameVerifier(); acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 8ecd353491..83fdcedf3e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -113,10 +113,6 @@ public static boolean defaultRemoveQueryParamOnRedirect() { return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); } - public static HostnameVerifier defaultHostnameVerifier() { - return new DefaultHostnameVerifier(); - } - public static boolean defaultSpdyEnabled() { return Boolean.getBoolean(ASYNC_CLIENT + "spdyEnabled"); } diff --git a/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java deleted file mode 100644 index d32424daf9..0000000000 --- a/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.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 cec8290eb87c56100656f40c85416a0432ded6e1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 14:58:52 +0200 Subject: [PATCH 0174/2070] minor clean up --- .../request/timeout/ReadTimeoutTimerTask.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java index c500bdd369..df77acd780 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -37,36 +37,31 @@ public ReadTimeoutTimerTask(// @Override public void run(Timeout timeout) throws Exception { - if (requestSender.isClosed()) { + + if (requestSender.isClosed() || nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } - if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - - long now = millisTime(); + long now = millisTime(); - long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); - long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; + long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; - if (durationBeforeCurrentReadTimeout <= 0L) { - // idleConnectionTimeout reached - String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; - long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); - expire(message, durationSinceLastTouch); - nettyResponseFuture.setIdleConnectionTimeoutReached(); + if (durationBeforeCurrentReadTimeout <= 0L) { + // idleConnectionTimeout reached + String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; + long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); + expire(message, durationSinceLastTouch); + nettyResponseFuture.setIdleConnectionTimeoutReached(); - } else if (currentReadTimeoutInstant < requestTimeoutInstant) { - // reschedule - timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); - - } else { - // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.readTimeout = null; - } + } else if (currentReadTimeoutInstant < requestTimeoutInstant) { + // reschedule + timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { - timeoutsHolder.cancel(); + // otherwise, no need to reschedule: requestTimeout will happen sooner + timeoutsHolder.readTimeout = null; } } } From eaf6109e3081d56df0da99b305d80d8d00bac3e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:17:23 +0200 Subject: [PATCH 0175/2070] Fix NPE when passing a null charset, close #651 --- .../asynchttpclient/multipart/StringPart.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index a6d60b7153..9ed500a561 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -18,6 +18,8 @@ import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; +import org.asynchttpclient.util.StandardCharsets; + public class StringPart extends PartBase { /** @@ -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 @@ -40,6 +42,10 @@ public class StringPart extends PartBase { */ private final byte[] content; + private static Charset charsetOrDefault(String charset) { + return charset == null ? DEFAULT_CHARSET : Charset.forName(charset); + } + public StringPart(String name, String value, String charset) { this(name, value, charset, null); } @@ -58,15 +64,13 @@ public StringPart(String name, String value, String charset) { */ public StringPart(String name, String value, String charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); - if (value == null) { + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), DEFAULT_TRANSFER_ENCODING, contentId); + 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)); } /** From cb4b4c4cd8d77b30fb5704b31321e21bdca5cf76 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:30:33 +0200 Subject: [PATCH 0176/2070] comment --- .../providers/netty/request/body/BodyChunkedInput.java | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java index e48d6d8a13..a9b50bd404 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyChunkedInput.java @@ -51,6 +51,7 @@ public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception { if (endOfInput) { return null; } else { + // FIXME pass a visitor so we can directly pass a pooled ByteBuf ByteBuffer buffer = ByteBuffer.allocate(chunkSize); long r = body.read(buffer); if (r < 0L) { From 30e106a242ea8d407406bb6e85d72dd02098547b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:40:40 +0200 Subject: [PATCH 0177/2070] Clean up warnings --- .../org/asynchttpclient/AsyncHttpClientConfigDefaults.java | 4 ---- .../java/org/asynchttpclient/util/ProxyHostnameChecker.java | 1 + .../test/java/org/asynchttpclient/async/util/TestUtils.java | 1 - .../asynchttpclient/websocket/CloseCodeReasonMessageTest.java | 4 ++-- .../providers/netty/request/NettyConnectListener.java | 2 +- .../providers/netty/request/NettyRequestSender.java | 2 ++ .../providers/netty/request/body/NettyBodyBody.java | 1 - 7 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 83fdcedf3e..36991bfa2d 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -14,10 +14,6 @@ import static org.asynchttpclient.util.MiscUtils.getBoolean; -import org.asynchttpclient.util.DefaultHostnameVerifier; - -import javax.net.ssl.HostnameVerifier; - public final class AsyncHttpClientConfigDefaults { private AsyncHttpClientConfigDefaults() { diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java b/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java index 1355d9084f..3796911298 100644 --- a/api/src/main/java/org/asynchttpclient/util/ProxyHostnameChecker.java +++ b/api/src/main/java/org/asynchttpclient/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); diff --git a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java index 7c9b46c50b..ad87080b85 100644 --- a/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java +++ b/api/src/test/java/org/asynchttpclient/async/util/TestUtils.java @@ -3,7 +3,6 @@ import static org.testng.Assert.assertEquals; import org.apache.commons.io.FileUtils; -import org.asynchttpclient.async.HostnameVerifierTest; import org.asynchttpclient.util.StandardCharsets; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; diff --git a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java index a2b1519d9d..d5640b10ef 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java @@ -109,7 +109,7 @@ public void wrongStatusCode() throws Throwable { 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() { + c.prepareGet("http://apache.org/").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -149,7 +149,7 @@ public void wrongProtocolCode() throws Throwable { 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() { + c.prepareGet("ws://www.google.com").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b463d70d55..b6d4ee27a7 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -87,7 +87,7 @@ private void writeRequest(Channel channel) { public void onFutureSuccess(final Channel channel) throws ConnectException { Channels.setAttribute(channel, future); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); - final SslHandler sslHandler = channelManager.getSslHandler(channel.pipeline()); + final SslHandler sslHandler = ChannelManager.getSslHandler(channel.pipeline()); if (hostnameVerifier != null && sslHandler != null) { final String host = future.getURI().getHost(); sslHandler.handshakeFuture().addListener(new GenericFutureListener>() { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 207d0596e6..68da7ab765 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -141,6 +141,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// * 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,// @@ -443,6 +444,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()) { try { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 43c39cfea7..94adb45b88 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -19,7 +19,6 @@ import org.asynchttpclient.RandomAccessBody; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.channel.ChannelManager; -import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; import org.asynchttpclient.providers.netty.request.body.FeedableBodyGenerator.FeedListener; From 2ca8a3d0edf4842a1c07be6889467bfc9d727a87 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:56:47 +0200 Subject: [PATCH 0178/2070] Have Parts take a java.nio.Charset instead of a String, close #652 --- .../multipart/AbstractFilePart.java | 3 ++- .../multipart/ByteArrayPart.java | 9 +++++---- .../asynchttpclient/multipart/FilePart.java | 15 ++++++++------- .../org/asynchttpclient/multipart/Part.java | 3 ++- .../asynchttpclient/multipart/PartBase.java | 19 ++++++++++--------- .../asynchttpclient/multipart/StringPart.java | 10 +++++----- .../async/AsyncProvidersBasicTest.java | 2 +- .../async/FastUnauthorizedUploadTest.java | 2 +- .../async/FilePartLargeFileTest.java | 4 ++-- .../async/MultipartUploadTest.java | 14 +++++++------- .../async/SimpleAsyncHttpClientTest.java | 4 ++-- .../multipart/MultipartBodyTest.java | 7 ++++--- 12 files changed, 49 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java index 8e711d3a98..c3a2533603 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java +++ b/api/src/main/java/org/asynchttpclient/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 transfertEncoding) { + public AbstractFilePart(String name, String contentType, Charset charset, String contentId, String transfertEncoding) { super(name,// contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// charset,// diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java index bc4660cb8e..f3dc0f11c7 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java index 3ea77ed562..359ec21f72 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java @@ -12,9 +12,6 @@ */ package org.asynchttpclient.multipart; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -23,6 +20,10 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; 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/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java index 66758c7df8..4a5a2d90b8 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/Part.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java index 6273fce8ed..a241df72a9 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java +++ b/api/src/main/java/org/asynchttpclient/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. @@ -54,14 +55,14 @@ public abstract class PartBase implements 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 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; } @@ -89,10 +90,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(); + Charset charSet = getCharset(); if (charSet != null) { visitor.withBytes(CHARSET_BYTES); - visitor.withBytes(charSet.getBytes(US_ASCII)); + visitor.withBytes(charset.name().getBytes(US_ASCII)); } } } @@ -186,7 +187,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())// @@ -204,8 +205,8 @@ public String getContentType() { } @Override - public String getCharSet() { - return this.charSet; + public Charset getCharset() { + return this.charset; } @Override diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java index 9ed500a561..eb6b90b329 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java +++ b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java @@ -42,11 +42,11 @@ public class StringPart extends PartBase { */ private final byte[] content; - 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; } - public StringPart(String name, String value, String charset) { + public StringPart(String name, String value, Charset charset) { this(name, value, charset, null); } @@ -62,9 +62,9 @@ public StringPart(String name, String value, String charset) { * @param contentId * the content id */ - public StringPart(String name, String value, String charset, String contentId) { + public StringPart(String name, String value, Charset charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), DEFAULT_TRANSFER_ENCODING, contentId); + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset), DEFAULT_TRANSFER_ENCODING, contentId); if (value == null) throw new NullPointerException("value"); if (value.indexOf(0) != -1) diff --git a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java index 301074edc6..b4ae251628 100755 --- a/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java +++ b/api/src/test/java/org/asynchttpclient/async/AsyncProvidersBasicTest.java @@ -659,7 +659,7 @@ public void asyncDoPostMultiPartTest() throws Exception { 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/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java index 18011253cc..59ab429241 100644 --- a/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FastUnauthorizedUploadTest.java @@ -53,7 +53,7 @@ public void testUnauthorizedWhileUploading() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8.name())).execute() + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8)).execute() .get(); assertEquals(response.getStatusCode(), 401); } finally { diff --git a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java index 9783fc4fcf..b2f378f9c7 100644 --- a/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java +++ b/api/src/test/java/org/asynchttpclient/async/FilePartLargeFileTest.java @@ -64,7 +64,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H public void testPutImageFile() throws Exception { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100 * 6000).build()); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", LARGE_IMAGE_FILE, "application/octet-stream", StandardCharsets.UTF_8)).execute().get(); assertEquals(response.getStatusCode(), 200); } finally { client.close(); @@ -77,7 +77,7 @@ public void testPutLargeTextFile() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8.name())).execute().get(); + Response response = client.preparePut(getTargetUrl()).addBodyPart(new FilePart("test", file, "application/octet-stream", StandardCharsets.UTF_8)).execute().get(); assertEquals(response.getStatusCode(), 200); } finally { client.close(); diff --git a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java index 1222e4408d..ad063a9782 100644 --- a/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java +++ b/api/src/test/java/org/asynchttpclient/async/MultipartUploadTest.java @@ -174,16 +174,16 @@ public void testSendingSmallFilesAndByteArray() { RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl("http://localhost/" + ":" + port1 + "/upload/bob"); - builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", StandardCharsets.UTF_8.name())); + builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", StandardCharsets.UTF_8)); builder.addBodyPart(new FilePart("file2", testResource2File, "application/x-gzip", null)); - builder.addBodyPart(new StringPart("Name", "Dominic", StandardCharsets.UTF_8.name())); - builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", StandardCharsets.UTF_8.name())); + builder.addBodyPart(new StringPart("Name", "Dominic", StandardCharsets.UTF_8)); + builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", StandardCharsets.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(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8, "bytearray.txt")); Request r = builder.build(); diff --git a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java index a7f4615795..59b4caa6ae 100644 --- a/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java +++ b/api/src/test/java/org/asynchttpclient/async/SimpleAsyncHttpClientTest.java @@ -307,7 +307,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(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); @@ -331,7 +331,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(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); diff --git a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java index 9de0bfa50f..40aa2db636 100644 --- a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java @@ -12,9 +12,10 @@ */ package org.asynchttpclient.multipart; +import static org.asynchttpclient.util.StandardCharsets.UTF_8; + import org.asynchttpclient.Body; import org.asynchttpclient.FluentCaseInsensitiveStringsMap; -import org.asynchttpclient.util.StandardCharsets; import org.testng.Assert; import org.testng.annotations.Test; @@ -37,10 +38,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", UTF_8, "fileName")); // add a string - parts.add(new StringPart("stringPart", "testString", StandardCharsets.UTF_8.name())); + parts.add(new StringPart("stringPart", "testString", UTF_8)); compareContentLength(parts); } From 54950d775882c72dce5e64cfc5d2fddd08e7390e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 13:32:08 +0200 Subject: [PATCH 0179/2070] minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 2a87ac293b..2c2940b168 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -196,29 +196,28 @@ 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); } } } - if (last) { + if (last) textBuffer.setLength(0); - } } public void onError(Throwable t) { From 6807f5b146314fa09007706e2808178a8f396918 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 11:58:32 +0200 Subject: [PATCH 0180/2070] minor clean up --- .../providers/netty/handler/WebSocketProtocol.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index e8e0917338..fbacb05374 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -86,12 +86,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 4996b444ea42e3bdfd5f7fb9d650c5d00e99cc0e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:19:17 +0200 Subject: [PATCH 0181/2070] RandomAccessBody.transferTo count is actually unused (Long.MAX_VALUE) --- api/src/main/java/org/asynchttpclient/Body.java | 1 + .../main/java/org/asynchttpclient/RandomAccessBody.java | 4 +--- .../org/asynchttpclient/generators/FileBodyGenerator.java | 8 +++----- .../java/org/asynchttpclient/multipart/MultipartBody.java | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Body.java b/api/src/main/java/org/asynchttpclient/Body.java index 5a39306b2d..9ee63021da 100644 --- a/api/src/main/java/org/asynchttpclient/Body.java +++ b/api/src/main/java/org/asynchttpclient/Body.java @@ -36,6 +36,7 @@ public interface Body extends Closeable { * @return The non-negative number of bytes actually read or {@code -1} if the body has been read completely. * @throws IOException If the chunk could not be read. */ + // FIXME introduce a visitor pattern so that Netty can pass a pooled buffer long read(ByteBuffer buffer) throws IOException; /** diff --git a/api/src/main/java/org/asynchttpclient/RandomAccessBody.java b/api/src/main/java/org/asynchttpclient/RandomAccessBody.java index 6cdc699485..fa74e9e684 100644 --- a/api/src/main/java/org/asynchttpclient/RandomAccessBody.java +++ b/api/src/main/java/org/asynchttpclient/RandomAccessBody.java @@ -26,13 +26,11 @@ public interface RandomAccessBody extends Body { * * @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/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java index 007a993206..dd97ec217b 100644 --- a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java +++ b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java @@ -25,6 +25,7 @@ /** * Creates a request body from the contents of a file. */ +//Not used by Netty public class FileBodyGenerator implements BodyGenerator { private final File file; @@ -89,11 +90,8 @@ public long read(ByteBuffer buffer) throws IOException { return channel.read(buffer); } - public long transferTo(long position, long count, WritableByteChannel target) throws IOException { - if (count > length) { - count = length; - } - return channel.transferTo(position, count, target); + public long transferTo(long position, WritableByteChannel target) throws IOException { + return channel.transferTo(position, length, target); } public void close() throws IOException { diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java index 1515409364..1b732b9390 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java +++ b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java @@ -69,7 +69,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; From 6fd6367156fc8f129e1c50395eb626a05131cf77 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:22:01 +0200 Subject: [PATCH 0182/2070] Remove useless synchronized --- .../multipart/MultipartUtils.java | 78 +++++++++---------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java index b546d1f7ba..d1f3ace5dc 100644 --- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java +++ b/api/src/main/java/org/asynchttpclient/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 f22ad62066cfd1bf3d7415251af2c2732db34acf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:23:36 +0200 Subject: [PATCH 0183/2070] Fix build --- .../providers/netty/request/body/BodyFileRegion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 49fabeef29..010625f95b 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -52,7 +52,7 @@ public long transfered() { @Override public long transferTo(WritableByteChannel target, long position) throws IOException { - long written = body.transferTo(position, Long.MAX_VALUE, target); + long written = body.transferTo(position, target); if (written > 0) { transfered += written; } From b5af568f378e5b037f74610787eb957bf0bfd162 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:37:44 +0200 Subject: [PATCH 0184/2070] Only set Content-Length is strictly positive --- .../providers/netty/request/NettyRequestFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 2b26b06e2e..fa971cf010 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -281,7 +281,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 613a83a3b6285bcacb0be27cb98222ec070ec40a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 13:43:53 +0200 Subject: [PATCH 0185/2070] closeSilently --- .../main/java/org/asynchttpclient/Body.java | 7 ---- .../org/asynchttpclient/BodyConsumer.java | 9 +----- .../SimpleAsyncHttpClient.java | 32 ++++++++----------- .../ResumableRandomAccessFileListener.java | 14 +++----- .../PropertiesBasedResumableProcessor.java | 17 ++++------ .../org/asynchttpclient/util/MiscUtils.java | 11 ++++++- .../multipart/MultipartBodyTest.java | 2 -- .../netty/request/body/BodyFileRegion.java | 10 +++--- .../netty/request/body/NettyBodyBody.java | 29 +++++++---------- .../netty/request/body/NettyFileBody.java | 19 ++--------- .../request/body/NettyInputStreamBody.java | 8 ++--- 11 files changed, 56 insertions(+), 102 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/Body.java b/api/src/main/java/org/asynchttpclient/Body.java index 9ee63021da..422e365e2f 100644 --- a/api/src/main/java/org/asynchttpclient/Body.java +++ b/api/src/main/java/org/asynchttpclient/Body.java @@ -38,11 +38,4 @@ public interface Body extends Closeable { */ // FIXME introduce a visitor pattern so that Netty can pass a pooled buffer long read(ByteBuffer buffer) throws IOException; - - /** - * Releases any resources associated with this body. - * - * @throws IOException - */ - void close() throws IOException; } diff --git a/api/src/main/java/org/asynchttpclient/BodyConsumer.java b/api/src/main/java/org/asynchttpclient/BodyConsumer.java index 0e93652bb1..190c586ae7 100644 --- a/api/src/main/java/org/asynchttpclient/BodyConsumer.java +++ b/api/src/main/java/org/asynchttpclient/BodyConsumer.java @@ -25,15 +25,8 @@ public interface BodyConsumer extends Closeable { /** * Consume the received bytes. * - * @param byteBuffer a {@link ByteBuffer} represntation of the response's chunk. + * @param byteBuffer a {@link ByteBuffer} representation of the response's chunk. * @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/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 25b9be4075..e90cee8f6b 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -12,17 +12,7 @@ */ package org.asynchttpclient; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.multipart.Part; -import org.asynchttpclient.resumable.ResumableAsyncHandler; -import org.asynchttpclient.resumable.ResumableIOExceptionFilter; -import org.asynchttpclient.simple.HeaderMap; -import org.asynchttpclient.simple.SimpleAHCTransferListener; -import org.asynchttpclient.uri.UriComponents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.SSLContext; +import static org.asynchttpclient.util.MiscUtils.closeSilently; import java.io.Closeable; import java.io.IOException; @@ -32,6 +22,16 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import javax.net.ssl.SSLContext; + +import org.asynchttpclient.cookie.Cookie; +import org.asynchttpclient.multipart.Part; +import org.asynchttpclient.resumable.ResumableAsyncHandler; +import org.asynchttpclient.resumable.ResumableIOExceptionFilter; +import org.asynchttpclient.simple.HeaderMap; +import org.asynchttpclient.simple.SimpleAHCTransferListener; +import org.asynchttpclient.uri.UriComponents; + /** * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link AsyncHttpClientConfig}, * {@link Realm}, {@link ProxyServer} and {@link AsyncHandler}. You can @@ -64,7 +64,6 @@ */ public class SimpleAsyncHttpClient implements Closeable { - private final static Logger logger = LoggerFactory.getLogger(SimpleAsyncHttpClient.class); private final AsyncHttpClientConfig config; private final RequestBuilder requestBuilder; private AsyncHttpClient asyncHttpClient; @@ -778,13 +777,8 @@ 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); - } + if (bodyConsumer != null) + closeSilently(bodyConsumer); } @Override diff --git a/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java b/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java index e8a63a0f6c..7b0dd64b95 100644 --- a/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java +++ b/api/src/main/java/org/asynchttpclient/extra/ResumableRandomAccessFileListener.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.extra; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + import org.asynchttpclient.resumable.ResumableListener; import java.io.IOException; @@ -52,13 +54,7 @@ public void onBytesReceived(ByteBuffer buffer) throws IOException { * {@inheritDoc} */ public void onAllBytesReceived() { - if (file != null) { - try { - file.close(); - } catch (IOException e) { - ; - } - } + closeSilently(file); } /** @@ -68,9 +64,7 @@ public long length() { try { return file.length(); } catch (IOException e) { - ; + return 0; } - return 0; } - } diff --git a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java index 9f6959f608..030a95fb7f 100644 --- a/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java +++ b/api/src/main/java/org/asynchttpclient/resumable/PropertiesBasedResumableProcessor.java @@ -12,18 +12,19 @@ */ package org.asynchttpclient.resumable; -import org.asynchttpclient.util.StandardCharsets; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.asynchttpclient.util.MiscUtils.closeSilently; 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; +import org.asynchttpclient.util.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A {@link org.asynchttpclient.resumable.ResumableAsyncHandler.ResumableProcessor} which use a properties file * to store the download index information. @@ -81,12 +82,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/api/src/main/java/org/asynchttpclient/util/MiscUtils.java b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java index db508f8513..1943f9939b 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java @@ -12,6 +12,8 @@ */ package org.asynchttpclient.util; +import java.io.Closeable; +import java.io.IOException; import java.util.Collection; import java.util.Map; @@ -46,6 +48,13 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { } public static T withDefault(T value, T defaults) { - return value != null? value : value; + return value != null ? value : value; + } + + public static void closeSilently(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + } } } diff --git a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java index 40aa2db636..3eeb05bbe6 100644 --- a/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java +++ b/api/src/test/java/org/asynchttpclient/multipart/MultipartBodyTest.java @@ -62,8 +62,6 @@ private static File getTestfile() { private static void compareContentLength(final List parts) { Assert.assertNotNull(parts); // get expected values - - // get real bytes final Body multipartBody = MultipartUtils.newMultipartBody(parts, new FluentCaseInsensitiveStringsMap()); final long expectedContentLength = multipartBody.getContentLength(); try { diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java index 010625f95b..b1d02275e4 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/BodyFileRegion.java @@ -13,6 +13,9 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + + import org.asynchttpclient.RandomAccessBody; import io.netty.channel.FileRegion; @@ -20,7 +23,6 @@ import java.io.IOException; import java.nio.channels.WritableByteChannel; - /** * Adapts a {@link RandomAccessBody} to Netty's {@link FileRegion}. */ @@ -61,10 +63,6 @@ public long transferTo(WritableByteChannel target, long position) throws IOExcep @Override protected void deallocate() { - try { - body.close(); - } catch (IOException e) { - // we tried - } + closeSilently(body); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java index 94adb45b88..96957591ab 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyBodyBody.java @@ -13,6 +13,15 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelProgressiveFuture; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.stream.ChunkedWriteHandler; + +import java.io.IOException; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Body; import org.asynchttpclient.BodyGenerator; @@ -22,21 +31,9 @@ import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; import org.asynchttpclient.providers.netty.request.body.FeedableBodyGenerator.FeedListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelProgressiveFuture; -import io.netty.handler.codec.http.LastHttpContent; -import io.netty.handler.stream.ChunkedWriteHandler; - -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; @@ -63,7 +60,7 @@ public String getContentType() { public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { Object msg; - if (!ChannelManager.isSslHandlerConfigured(channel.pipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { + if (body instanceof RandomAccessBody && !ChannelManager.isSslHandlerConfigured(channel.pipeline()) && !nettyConfig.isDisableZeroCopy()) { msg = new BodyFileRegion((RandomAccessBody) body); } else { @@ -83,11 +80,7 @@ public void onContentAdded() { writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java index 7b5234e5cd..44a5349a7e 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyFileBody.java @@ -13,6 +13,7 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelProgressiveFuture; @@ -30,13 +31,9 @@ import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; 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; @@ -88,23 +85,13 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien } writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture cf) { - try { - // FIXME probably useless in Netty 4 - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(raf); super.operationComplete(cf); } }); channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } catch (IOException ex) { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - } - } + closeSilently(raf); throw ex; } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java index 4412cd9bf4..9f7d841996 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/body/NettyInputStreamBody.java @@ -13,6 +13,8 @@ */ package org.asynchttpclient.providers.netty.request.body; +import static org.asynchttpclient.util.MiscUtils.closeSilently; + import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; import org.asynchttpclient.providers.netty.request.ProgressListener; @@ -69,11 +71,7 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien channel.write(new ChunkedStream(is), channel.newProgressivePromise()).addListener( new ProgressListener(config, future.getAsyncHandler(), future, false, getContentLength()) { public void operationComplete(ChannelProgressiveFuture cf) { - try { - is.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(is); super.operationComplete(cf); } }); From f822b0a68601684dbb36e40c5bef1e2a9774d68f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:06:50 +0200 Subject: [PATCH 0186/2070] minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 2c2940b168..a9f6eefe63 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -34,7 +34,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; 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(); @@ -150,29 +151,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); } } } @@ -189,9 +189,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; } } @@ -202,13 +202,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); @@ -221,11 +219,11 @@ 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); } } @@ -236,14 +234,14 @@ public void onClose() { } public void onClose(int code, String reason) { - for (WebSocketListener l : listeners) { + for (WebSocketListener listener : listeners) { try { - if (l instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(l).onClose(this, code, reason); + if (listener instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(listener).onClose(this, code, reason); } - l.onClose(this); + listener.onClose(this); } catch (Throwable t) { - l.onError(t); + listener.onError(t); } } } From d7db2b79b8f9aeb2f4fbe01c3d69a62a07aead21 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:19:37 +0200 Subject: [PATCH 0187/2070] minor clean up --- .../websocket/WebSocketUpgradeHandler.java | 87 +++++-------------- .../providers/netty/ws/NettyWebSocket.java | 7 +- 2 files changed, 24 insertions(+), 70 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index 69e7664d76..bbf13b0167 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -27,22 +27,13 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, AsyncHandler { private WebSocket webSocket; - private final ConcurrentLinkedQueue l; - @SuppressWarnings("unused") - private final String protocol; - @SuppressWarnings("unused") - private final long maxByteSize; - @SuppressWarnings("unused") - 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; - private WebSocketUpgradeHandler(Builder b) { - l = b.l; - protocol = b.protocol; - maxByteSize = b.maxByteSize; - maxTextSize = b.maxTextSize; + public WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + this.listeners = listeners; } /** @@ -93,8 +84,9 @@ public final STATE onHeadersReceived(HttpResponseHeaders headers) throws Excepti public final 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; } @@ -111,9 +103,9 @@ public final WebSocket onCompleted() throws Exception { @Override public final 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); } @@ -123,11 +115,11 @@ public final void onSuccess(WebSocket webSocket) { */ @Override public final void onFailure(Throwable t) { - for (WebSocketListener w : l) { + for (WebSocketListener listener : listeners) { if (!ok.get() && webSocket != null) { - webSocket.addWebSocketListener(w); + webSocket.addWebSocketListener(listener); } - w.onError(t); + listener.onError(t); } } @@ -136,13 +128,13 @@ public final void onClose(WebSocket webSocket, int status, String reasonPhrase) 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); } } } @@ -151,10 +143,8 @@ public final 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} @@ -163,7 +153,7 @@ public final static class Builder { * @return this */ public Builder addWebSocketListener(WebSocketListener listener) { - l.add(listener); + listeners.add(listener); return this; } @@ -174,40 +164,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; } @@ -217,7 +174,7 @@ public Builder setMaxTextSize(long maxTextSize) { * @return a {@link WebSocketUpgradeHandler} */ public WebSocketUpgradeHandler build() { - return new WebSocketUpgradeHandler(this); + return new WebSocketUpgradeHandler(listeners); } } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index a9f6eefe63..eaadbf589e 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -103,11 +103,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 From 55d6f217fe87cc3ce84613ea62ed92202da52f98 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:42:26 +0200 Subject: [PATCH 0188/2070] WebSocketUpgradeHandler doesn't need to be threadsafe --- .../websocket/WebSocketUpgradeHandler.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index bbf13b0167..c8fef8a02f 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java @@ -12,27 +12,28 @@ */ package org.asynchttpclient.websocket; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.HttpResponseBodyPart; import org.asynchttpclient.HttpResponseHeaders; import org.asynchttpclient.HttpResponseStatus; import org.asynchttpclient.UpgradeHandler; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; - /** * An {@link AsyncHandler} which is able to execute WebSocket upgrade. Use the Builder for configuring WebSocket options. */ 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; - public WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + public WebSocketUpgradeHandler(List listeners) { this.listeners = listeners; } @@ -144,7 +145,7 @@ public final void onClose(WebSocket webSocket, int status, String reasonPhrase) */ public final static class Builder { - private ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); + private List listeners = new ArrayList(); /** * Add a {@link WebSocketListener} that will be added to the {@link WebSocket} From e67c8625e57034de8948f5e3c30ddf40bae2dc96 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 01:58:12 +0200 Subject: [PATCH 0189/2070] Turn NettyWebSocket into an abstract class and introduce a Factory, close #656 --- .../websocket/WebSocketUpgradeHandler.java | 6 +- .../netty/NettyAsyncHttpProviderConfig.java | 46 +++-- .../netty/handler/WebSocketProtocol.java | 7 +- .../netty/ws/DefaultNettyWebSocket.java | 124 ++++++++++++++ .../providers/netty/ws/NettyWebSocket.java | 162 ++++-------------- 5 files changed, 202 insertions(+), 143 deletions(-) create mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java index c8fef8a02f..b612c9b0ac 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketUpgradeHandler.java +++ b/api/src/main/java/org/asynchttpclient/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; public WebSocketUpgradeHandler(List listeners) { @@ -46,7 +46,9 @@ public final void onThrowable(Throwable t) { } public boolean touchSuccess() { - return onSuccessCalled.getAndSet(true); + boolean prev = onSuccessCalled; + onSuccessCalled = true; + return prev; } /** diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 36659292ad..95eed7889f 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -13,13 +13,6 @@ */ package org.asynchttpclient.providers.netty; -import org.asynchttpclient.AsyncHttpProviderConfig; -import org.asynchttpclient.SSLEngineFactory; -import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; -import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; -import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; - import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; @@ -30,6 +23,15 @@ import java.util.Map; import java.util.Set; +import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.SSLEngineFactory; +import org.asynchttpclient.providers.netty.channel.pool.ChannelPool; +import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; +import org.asynchttpclient.providers.netty.ws.DefaultNettyWebSocket; +import org.asynchttpclient.providers.netty.ws.NettyWebSocket; + /** * This class can be used to pass Netty's internal configuration options. See * Netty documentation for more information. @@ -114,6 +116,18 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { } } + public static interface NettyWebSocketFactory { + NettyWebSocket newNettyWebSocket(Channel channel); + } + + public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { + + @Override + public NettyWebSocket newNettyWebSocket(Channel channel) { + return new DefaultNettyWebSocket(channel); + } + } + /** * Allow configuring the Netty's event loop. */ @@ -142,7 +156,7 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { private Timer nettyTimer; - private long handshakeTimeoutInMillis; + private long handshakeTimeout; private SSLEngineFactory sslEngineFactory; @@ -151,6 +165,8 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { */ private int chunkedFileChunkSize = 8192; + private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -248,11 +264,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 SSLEngineFactory getSslEngineFactory() { @@ -270,4 +286,12 @@ public int getChunkedFileChunkSize() { public void setChunkedFileChunkSize(int chunkedFileChunkSize) { this.chunkedFileChunkSize = chunkedFileChunkSize; } + + public NettyWebSocketFactory getNettyWebSocketFactory() { + return nettyWebSocketFactory; + } + + public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory) { + this.nettyWebSocketFactory = nettyWebSocketFactory; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index fbacb05374..bdedadd68c 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -42,7 +42,6 @@ import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; import org.asynchttpclient.providers.netty.response.NettyResponseStatus; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; -import org.asynchttpclient.util.StandardCharsets; import org.asynchttpclient.websocket.WebSocketUpgradeHandler; public final class WebSocketProtocol extends Protocol { @@ -59,7 +58,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); } @@ -140,9 +139,9 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + webSocket.onBinaryFragment(rp); } else { - webSocket.onTextFragment(buf.toString(StandardCharsets.UTF_8), frame.isFinalFragment()); + webSocket.onTextFragment(rp); } } finally { buf.release(); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java new file mode 100644 index 0000000000..11b8cfd133 --- /dev/null +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java @@ -0,0 +1,124 @@ +/* + * 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 org.asynchttpclient.providers.netty.ws; + + +import io.netty.channel.Channel; + +import java.io.ByteArrayOutputStream; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.util.StandardCharsets; +import org.asynchttpclient.websocket.WebSocketByteListener; +import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketTextListener; + +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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index eaadbf589e..c0d2a8d977 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -14,43 +14,39 @@ package org.asynchttpclient.providers.netty.ws; import static io.netty.buffer.Unpooled.wrappedBuffer; - -import org.asynchttpclient.websocket.WebSocket; -import org.asynchttpclient.websocket.WebSocketByteListener; -import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; -import org.asynchttpclient.websocket.WebSocketListener; -import org.asynchttpclient.websocket.WebSocketTextListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.Collection; + +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.websocket.WebSocket; +import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; +import org.asynchttpclient.websocket.WebSocketListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -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 public WebSocket sendMessage(byte[] message) { - channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -66,7 +62,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.writeAndFlush(new TextWebSocketFrame(message)); + channel.write(new TextWebSocketFrame(message)); return this; } @@ -77,13 +73,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } @@ -102,11 +98,11 @@ public WebSocket removeWebSocketListener(WebSocketListener l) { public int getMaxBufferSize() { return maxBufferSize; } - + public void setMaxBufferSize(int maxBufferSize) { this.maxBufferSize = Math.max(maxBufferSize, 8192); } - + @Override public boolean isOpen() { return channel.isOpen(); @@ -114,105 +110,16 @@ public boolean isOpen() { @Override public void close() { - onClose(); - listeners.clear(); - try { - channel.writeAndFlush(new CloseWebSocketFrame()); - channel.closeFuture().awaitUninterruptibly(); - } finally { - channel.close(); + if (channel.isOpen()) { + onClose(); + listeners.clear(); + channel.write(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); } } public void close(int statusCode, String reason) { onClose(statusCode, reason); listeners.clear(); - try { - channel.writeAndFlush(new CloseWebSocketFrame()); - channel.closeFuture().awaitUninterruptibly(); - } finally { - channel.close(); - } - } - - 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) { @@ -222,29 +129,32 @@ public void onError(Throwable t) { } catch (Throwable t2) { LOGGER.error("", t2); } - } } - public void onClose() { + protected void onClose() { onClose(1000, "Normal closure; the connection successfully completed whatever purpose for which it was created."); } public void onClose(int code, String reason) { - for (WebSocketListener listener : listeners) { + for (WebSocketListener l : listeners) { try { - if (listener instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(listener).onClose(this, code, reason); + if (l instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(l).onClose(this, code, reason); } - listener.onClose(this); + l.onClose(this); } catch (Throwable t) { - listener.onError(t); + l.onError(t); } } } @Override public String toString() { - return "NettyWebSocket{" + "channel=" + channel + '}'; + return "NettyWebSocket{channel=" + channel + '}'; } + + public abstract void onBinaryFragment(HttpResponseBodyPart part); + + public abstract void onTextFragment(HttpResponseBodyPart part); } From 920694d95d2a553f12c95b5cb84d0c8f6551926d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:54:46 +0200 Subject: [PATCH 0190/2070] Better log --- .../providers/netty/request/NettyConnectListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java index b6d4ee27a7..571803a658 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyConnectListener.java @@ -72,7 +72,7 @@ private void abortChannelPreemption(String poolKey) { private void writeRequest(Channel channel) { - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + LOGGER.debug("Request using non cached Channel '{}':\n{}\n", channel, future.getNettyRequest().getHttpRequest()); if (future.isDone()) { abortChannelPreemption(poolKey); From d6503ff1160debae0c7bfcc633776ffd5dcdf6d2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:55:04 +0200 Subject: [PATCH 0191/2070] Remove duplicate log --- .../asynchttpclient/providers/netty/handler/HttpProtocol.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 98be1659cb..531c3c6246 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -47,7 +47,6 @@ import org.asynchttpclient.providers.netty.channel.ChannelManager; import org.asynchttpclient.providers.netty.channel.Channels; import org.asynchttpclient.providers.netty.future.NettyResponseFuture; -import org.asynchttpclient.providers.netty.request.NettyRequest; import org.asynchttpclient.providers.netty.request.NettyRequestSender; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseHeaders; @@ -402,12 +401,10 @@ public void handle(final Channel channel, final NettyResponseFuture future, f return; } - NettyRequest nettyRequest = future.getNettyRequest(); AsyncHandler handler = future.getAsyncHandler(); try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - logger.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest.getHttpRequest(), response); // FIXME why do we buffer the response? I don't remember... future.setPendingResponse(response); return; From 148f202ff0f7e48a1cd5d8b81318f95fa782a60f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 12:14:40 +0200 Subject: [PATCH 0192/2070] WebSocket messaged have to be flushed --- .../providers/netty/ws/NettyWebSocket.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index c0d2a8d977..97068be924 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -46,7 +46,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -62,7 +62,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.write(new TextWebSocketFrame(message)); + channel.writeAndFlush(new TextWebSocketFrame(message)); return this; } @@ -73,13 +73,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } From 056127bbf40eff00970c523b63fea0b3e2ee8ea5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 12:15:50 +0200 Subject: [PATCH 0193/2070] Ensured Netty provider uses CONNECT when proxying ws, port #657 on master --- .../AsyncHttpClientConfig.java | 28 +++++++-------- .../AsyncHttpClientConfigBean.java | 2 +- .../AsyncHttpClientConfigDefaults.java | 6 ++-- .../util/AsyncHttpProviderUtils.java | 17 +++------ .../websocket/ProxyTunnellingTest.java | 36 +++++++++++-------- .../filters/AsyncHttpClientFilter.java | 8 +++-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 8 +++-- .../netty/request/NettyRequestFactory.java | 11 +++--- .../netty/request/NettyRequestSender.java | 3 +- .../providers/netty/util/HttpUtils.java | 4 +++ 11 files changed, 68 insertions(+), 57 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 8f1aefbf30..2a14d03f32 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -91,7 +91,7 @@ public class AsyncHttpClientConfig { protected boolean strict302Handling; protected ProxyServerSelector proxyServerSelector; - protected boolean useRelativeURIsWithSSLProxies; + protected boolean useRelativeURIsWithConnectProxies; protected boolean compressionEnabled; protected String userAgent; @@ -133,7 +133,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// boolean strict302Handling, // ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // - boolean useRelativeURIsWithSSLProxies, // + boolean useRelativeURIsWithConnectProxies, // boolean compressionEnabled, // String userAgent,// Realm realm,// @@ -167,7 +167,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; @@ -493,13 +493,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; } /** @@ -548,7 +548,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; @@ -962,15 +962,15 @@ public Builder setConnectionTTL(int connectionTTL) { } /** - * 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 or WebSocket proxy. * - * @param useRelativeURIsWithSSLProxies + * @param useRelativeURIsWithConnectProxies * @return this * * @since 1.7.2 */ - public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLProxies) { - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + public Builder setUseRelativeURIsWithConnectProxies(boolean useRelativeURIsWithConnectProxies) { + this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; return this; } @@ -1116,7 +1116,7 @@ else if (hostnameVerifier == null) strict302Handling, // applicationThreadPool, // proxyServerSelector, // - useRelativeURIsWithSSLProxies, // + useRelativeURIsWithConnectProxies, // compressionEnabled, // userAgent,// realm,// diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 150187cea6..0bb496f28e 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index 36991bfa2d..6733cd5c10 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/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/2.0"); } public static int defaultIoThreadMultiplier() { @@ -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/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java index d0066c2adf..46371cb8ac 100644 --- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java @@ -14,17 +14,16 @@ import static org.asynchttpclient.util.MiscUtils.isNonEmpty; -import org.asynchttpclient.AsyncHttpClientConfig; -import org.asynchttpclient.AsyncHttpProvider; -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.Request; -import org.asynchttpclient.uri.UriComponents; - import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.List; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.Request; +import org.asynchttpclient.uri.UriComponents; + /** * {@link org.asynchttpclient.AsyncHttpProvider} common utilities. */ @@ -113,12 +112,6 @@ public final static String getNonEmptyPath(UriComponents uri) { return isNonEmpty(uri.getPath()) ? uri.getPath() : "/"; } - 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=")) { diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index cdb6e38cad..1879d19302 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -17,6 +17,9 @@ import static org.asynchttpclient.async.util.TestUtils.newJettyHttpsServer; import static org.testng.Assert.assertEquals; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ProxyServer; @@ -24,13 +27,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.websocket.server.WebSocketHandler; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - /** * Proxy usage tests. */ @@ -38,8 +37,7 @@ public abstract class ProxyTunnellingTest extends AbstractBasicTest { private Server server2; - @BeforeClass(alwaysRun = true) - public void setUpGlobal() throws Exception { + public void setUpServers(boolean targetHttps) throws Exception { port1 = findFreePort(); server = newJettyHttpServer(port1); server.setHandler(new ConnectHandler()); @@ -47,7 +45,7 @@ public void setUpGlobal() throws Exception { port2 = findFreePort(); - server2 = newJettyHttpsServer(port2); + server2 = targetHttps ? newJettyHttpsServer(port2) : newJettyHttpServer(port2); server2.setHandler(getWebSocketHandler()); server2.start(); @@ -64,27 +62,37 @@ public void configure(WebSocketServletFactory factory) { }; } - @AfterClass(alwaysRun = true) + @AfterMethod(alwaysRun = true) public void tearDownGlobal() throws Exception { server.stop(); server2.stop(); } - protected String getTargetUrl() { - return String.format("wss://127.0.0.1:%d/", port2); + @Test(timeOut = 60000) + public void echoWSText() throws Exception { + runTest(false); } @Test(timeOut = 60000) - public void echoText() throws Exception { + public void echoWSSText() throws Exception { + runTest(true); + } + + private void runTest(boolean secure) throws Exception { + + setUpServers(secure); + + String targetUrl = String.format("%s://127.0.0.1:%d/", secure ? "wss" : "ws", port2); - ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); + // CONNECT happens over HTTP, not HTTPS + ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTP, "127.0.0.1", port1); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).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() { + WebSocket websocket = asyncHttpClient.prepareGet(targetUrl).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index 7d7f002699..e1d4c8f60f 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -210,6 +210,7 @@ private boolean sendAsGrizzlyRequest( final Request request = httpTxContext.getRequest(); final UriComponents uri = request.getURI(); boolean secure = Utils.isSecure(uri); + boolean isWebSocket = isWSRequest(httpTxContext.getRequestUri()); // If the request is secure, check to see if an error occurred during // the handshake. We have to do this here, as the error would occur @@ -219,7 +220,8 @@ private boolean sendAsGrizzlyRequest( return true; } - if (isUpgradeRequest(httpTxContext.getHandler()) && isWSRequest(httpTxContext.getRequestUri())) { + + if (isUpgradeRequest(httpTxContext.getHandler()) && isWebSocket) { httpTxContext.setWSRequest(true); convertToUpgradeRequest(httpTxContext); } @@ -238,8 +240,10 @@ private boolean sendAsGrizzlyRequest( if (method == Method.CONNECT) { final int port = uri.getPort(); requestPacket.setRequestURI(uri.getHost() + ':' + (port == -1 ? 443 : port)); - } else { + } else if ((secure || isWebSocket) && config.isUseRelativeURIsWithConnectProxies()) { requestPacket.setRequestURI(getNonEmptyPath(uri)); + } else { + requestPacket.setRequestURI(uri.toUrl()); } final BodyHandler bodyHandler = isPayloadAllowed(method) ? diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java index 531c3c6246..29770ecc63 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/HttpProtocol.java @@ -405,7 +405,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f try { if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - // FIXME why do we buffer the response? I don't remember... + // we buffer the response until we get the LastHttpContent future.setPendingResponse(response); return; diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index bdedadd68c..371c943206 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -72,6 +72,12 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; + // we buffer the response until we get the LastHttpContent + future.setPendingResponse(response); + + } else if (e instanceof LastHttpContent) { + HttpResponse response = future.getPendingResponse(); + future.setPendingResponse(null); HttpResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); @@ -151,8 +157,6 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } else { logger.debug("UpgradeHandler returned a null NettyWebSocket "); } - } else if (e instanceof LastHttpContent) { - // FIXME what to do with this kind of messages? } else { logger.error("Invalid message {}", e); } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index fa971cf010..bd2850be64 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -16,9 +16,9 @@ import static org.asynchttpclient.providers.netty.util.HttpUtils.isNTLM; import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; import static org.asynchttpclient.providers.netty.util.HttpUtils.isWebSocket; +import static org.asynchttpclient.providers.netty.util.HttpUtils.useProxyConnect; import static org.asynchttpclient.providers.netty.ws.WebSocketUtils.getKey; import static org.asynchttpclient.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static org.asynchttpclient.util.AsyncHttpProviderUtils.constructUserAgent; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getAuthority; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getNonEmptyPath; import static org.asynchttpclient.util.AsyncHttpProviderUtils.keepAliveHeaderValue; @@ -49,7 +49,6 @@ import org.asynchttpclient.generators.InputStreamBodyGenerator; import org.asynchttpclient.ntlm.NTLMEngine; import org.asynchttpclient.ntlm.NTLMEngineException; -import org.asynchttpclient.providers.netty.NettyAsyncHttpProvider; import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.request.body.NettyBody; import org.asynchttpclient.providers.netty.request.body.NettyBodyBody; @@ -77,7 +76,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 { @@ -322,10 +321,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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java index 68da7ab765..75a3def312 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestSender.java @@ -15,6 +15,7 @@ import static org.asynchttpclient.providers.netty.util.HttpUtils.WEBSOCKET; import static org.asynchttpclient.providers.netty.util.HttpUtils.isSecure; +import static org.asynchttpclient.providers.netty.util.HttpUtils.useProxyConnect; import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort; import static org.asynchttpclient.util.AsyncHttpProviderUtils.requestTimeout; import static org.asynchttpclient.util.ProxyUtils.avoidProxy; @@ -100,7 +101,7 @@ public ListenableFuture sendRequest(final Request request,// boolean resultOfAConnect = future != null && future.getNettyRequest() != null && 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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java index e13b7ee51b..baac5bddbd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/util/HttpUtils.java @@ -43,4 +43,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()); + } } From 2c38d0148108c4f1aae609a54f14bc8aa6e78818 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 15:02:53 +0200 Subject: [PATCH 0194/2070] Release 1.8.13 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fab0cd307c..2bb2b19ad0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Async Http Client library purpose is to allow Java applications to easily execut com.ning async-http-client - 1.8.12 + 1.8.13 ``` From 0e4aa68fb9917f60b88e114b41eb9f3b97b4babe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 15:59:10 +0200 Subject: [PATCH 0195/2070] Extract Fragment listening concern into dedicated interfaces, close #655 --- .../websocket/DefaultWebSocketListener.java | 14 -- .../WebSocketByteFragmentListener.java | 26 +++ .../websocket/WebSocketByteListener.java | 9 +- .../WebSocketTextFragmentListener.java | 26 +++ .../websocket/WebSocketTextListener.java | 8 - .../websocket/ByteMessageTest.java | 12 -- .../websocket/CloseCodeReasonMessageTest.java | 8 - .../websocket/ProxyTunnellingTest.java | 4 - .../websocket/TextMessageTest.java | 24 --- .../AHCWebSocketListenerAdapter.java | 8 - .../netty/NettyAsyncHttpProviderConfig.java | 3 +- .../netty/ws/DefaultNettyWebSocket.java | 124 ------------ .../providers/netty/ws/NettyWebSocket.java | 186 +++++++++++++++--- 13 files changed, 217 insertions(+), 235 deletions(-) create mode 100644 api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java create mode 100644 api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java delete mode 100644 providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java diff --git a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java index 864bb32df8..7e465acffa 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/DefaultWebSocketListener.java @@ -33,13 +33,6 @@ public class DefaultWebSocketListener implements WebSocketByteListener, WebSocke public void onMessage(byte[] message) { } - /** - * {@inheritDoc} - */ - @Override - public void onFragment(byte[] fragment, boolean last) { - } - // -------------------------------------- Methods from WebSocketPingListener /** @@ -67,13 +60,6 @@ public void onPong(byte[] message) { public void onMessage(String message) { } - /** - * {@inheritDoc} - */ - @Override - public void onFragment(String fragment, boolean last) { - } - // ------------------------------------------ Methods from WebSocketListener /** diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteFragmentListener.java new file mode 100644 index 0000000000..9988115b25 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.websocket; + +import org.asynchttpclient.HttpResponseBodyPart; + +/** + * Invoked when WebSocket binary fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketByteFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java index 04dd4075ec..99fb4cede9 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java +++ b/api/src/main/java/org/asynchttpclient/websocket/WebSocketByteListener.java @@ -19,15 +19,8 @@ public interface WebSocketByteListener extends WebSocketListener { /** * Invoked when bytes are available. + * * @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/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextFragmentListener.java new file mode 100644 index 0000000000..a71f9364b4 --- /dev/null +++ b/api/src/main/java/org/asynchttpclient/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 org.asynchttpclient.websocket; + +import org.asynchttpclient.HttpResponseBodyPart; + +/** + * Invoked when WebSocket text fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketTextFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java b/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java index 2ea133b1ec..7f8242c74d 100644 --- a/api/src/main/java/org/asynchttpclient/websocket/WebSocketTextListener.java +++ b/api/src/main/java/org/asynchttpclient/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/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java index 4272b3ac48..d1078047ec 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ByteMessageTest.java @@ -64,9 +64,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.sendMessage("ECHO".getBytes()); @@ -115,9 +112,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()); @@ -167,9 +161,6 @@ public void onMessage(byte[] message) { latch.countDown(); } - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); latch.await(); @@ -215,9 +206,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/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java index d5640b10ef..5ab3ca228d 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/CloseCodeReasonMessageTest.java @@ -115,10 +115,6 @@ public void wrongStatusCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -155,10 +151,6 @@ public void wrongProtocolCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index 1879d19302..55c54970e4 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -100,10 +100,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/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java index 2ec3c20e3d..31d740c5ad 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/TextMessageTest.java @@ -184,10 +184,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -228,10 +224,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -254,10 +246,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -298,10 +286,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { websocket.sendTextMessage("ECHO").sendTextMessage("ECHO"); @@ -340,10 +324,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } @@ -386,10 +366,6 @@ public void onMessage(String message) { textLatch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java index 1a2f2122b2..1d2dd1291c 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/websocket/AHCWebSocketListenerAdapter.java @@ -128,10 +128,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); @@ -152,10 +148,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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 95eed7889f..38aa908fa9 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -29,7 +29,6 @@ import org.asynchttpclient.providers.netty.response.EagerNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyNettyResponseBodyPart; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; -import org.asynchttpclient.providers.netty.ws.DefaultNettyWebSocket; import org.asynchttpclient.providers.netty.ws.NettyWebSocket; /** @@ -124,7 +123,7 @@ public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override public NettyWebSocket newNettyWebSocket(Channel channel) { - return new DefaultNettyWebSocket(channel); + return new NettyWebSocket(channel); } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java deleted file mode 100644 index 11b8cfd133..0000000000 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/DefaultNettyWebSocket.java +++ /dev/null @@ -1,124 +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 org.asynchttpclient.providers.netty.ws; - - -import io.netty.channel.Channel; - -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.asynchttpclient.HttpResponseBodyPart; -import org.asynchttpclient.util.StandardCharsets; -import org.asynchttpclient.websocket.WebSocketByteListener; -import org.asynchttpclient.websocket.WebSocketListener; -import org.asynchttpclient.websocket.WebSocketTextListener; - -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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 97068be924..34bc1b1c33 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -14,6 +14,7 @@ package org.asynchttpclient.providers.netty.ws; import static io.netty.buffer.Unpooled.wrappedBuffer; +import static org.asynchttpclient.util.StandardCharsets.UTF_8; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; @@ -22,22 +23,40 @@ import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.websocket.WebSocket; +import org.asynchttpclient.websocket.WebSocketByteFragmentListener; +import org.asynchttpclient.websocket.WebSocketByteListener; import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketTextFragmentListener; +import org.asynchttpclient.websocket.WebSocketTextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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; @@ -46,7 +65,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -62,7 +81,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.writeAndFlush(new TextWebSocketFrame(message)); + channel.write(new TextWebSocketFrame(message)); return this; } @@ -73,36 +92,24 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); - return this; - } - - @Override - public WebSocket addWebSocketListener(WebSocketListener l) { - listeners.add(l); - return this; - } - - @Override - public WebSocket removeWebSocketListener(WebSocketListener l) { - listeners.remove(l); + channel.write(new PongWebSocketFrame(wrappedBuffer(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(); @@ -153,8 +160,141 @@ 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(byte[] buffer) { + bufferSize += buffer.length; + 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(byte[] message) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) + WebSocketByteListener.class.cast(listener).onMessage(message); + } + } + + private void notifyTextListeners(byte[] bytes) { + String message = new String(bytes, 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) { + byte[] fragment = NettyResponseBodyPart.class.cast(part).getBodyPartBytes(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyByteListeners(fragment); + + } else { + bufferFragment(fragment); + notifyByteListeners(fragmentsBytes()); + } + + reset(); + + } else + bufferFragment(fragment); + } + } + + private byte[] fragmentsBytes() { + ByteArrayOutputStream os = new ByteArrayOutputStream(bufferSize); + for (byte[] bytes : _fragments) + try { + os.write(bytes); + } catch (IOException e) { + // yeah, right + } + return os.toByteArray(); + } + + public void onTextFragment(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextFragmentListener) + WebSocketTextFragmentListener.class.cast(listener).onFragment(part); + } + + if (interestedInTextMessages) { + byte[] fragment = NettyResponseBodyPart.class.cast(part).getBodyPartBytes(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyTextListeners(fragment); + + } else { + bufferFragment(fragment); + notifyTextListeners(fragmentsBytes()); + } + + reset(); + + } else + bufferFragment(fragment); + } + } } From 5a6c1ea9f1d6a35211f320c345cafd6a3a610597 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:00:25 +0200 Subject: [PATCH 0196/2070] Regression: writeAndFlush --- .../providers/netty/ws/NettyWebSocket.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 34bc1b1c33..98789d0906 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -65,7 +65,7 @@ public NettyWebSocket(Channel channel, Collection listeners) @Override public WebSocket sendMessage(byte[] message) { - channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); + channel.writeAndFlush(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } @@ -81,7 +81,7 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { @Override public WebSocket sendTextMessage(String message) { - channel.write(new TextWebSocketFrame(message)); + channel.writeAndFlush(new TextWebSocketFrame(message)); return this; } @@ -92,13 +92,13 @@ public WebSocket streamText(String fragment, boolean last) { @Override public WebSocket sendPing(byte[] payload) { - channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } @Override public WebSocket sendPong(byte[] payload) { - channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); + channel.writeAndFlush(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } @@ -120,7 +120,7 @@ public void close() { if (channel.isOpen()) { onClose(); listeners.clear(); - channel.write(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); + channel.writeAndFlush(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); } } From ce539ee0954329b92bff5e2237bf1836cb526524 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:03:43 +0200 Subject: [PATCH 0197/2070] Netty websocket streaming, close #518 --- .../providers/netty/ws/NettyWebSocket.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 98789d0906..88357866bd 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -71,12 +71,14 @@ public WebSocket sendMessage(byte[] message) { @Override public WebSocket stream(byte[] fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + channel.writeAndFlush(new BinaryWebSocketFrame(last, 0, wrappedBuffer(fragment))); + 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."); + channel.writeAndFlush(new BinaryWebSocketFrame(last, 0, wrappedBuffer(fragment, offset, len))); + return this; } @Override @@ -87,7 +89,8 @@ public WebSocket sendTextMessage(String message) { @Override public WebSocket streamText(String fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + channel.writeAndFlush(new TextWebSocketFrame(last, 0, fragment)); + return this; } @Override From 7a067549012c4474a1a01c8c9beaf45c471962bb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:28:38 +0200 Subject: [PATCH 0198/2070] Notify Pings and Pongs, close #517 --- .../netty/handler/WebSocketProtocol.java | 25 ++++++++++++------- .../providers/netty/ws/NettyWebSocket.java | 18 +++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 371c943206..7dfbbe0690 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -22,6 +22,9 @@ import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import java.io.IOException; @@ -74,7 +77,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr HttpResponse response = (HttpResponse) e; // we buffer the response until we get the LastHttpContent future.setPendingResponse(response); - + } else if (e instanceof LastHttpContent) { HttpResponse response = future.getPendingResponse(); future.setPendingResponse(null); @@ -115,8 +118,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers() - .get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + 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))); } @@ -141,13 +143,17 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr ByteBuf buf = frame.content(); if (buf != null && buf.readableBytes() > 0) { try { - NettyResponseBodyPart rp = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, frame.isFinalFragment()); - handler.onBodyPartReceived(rp); + NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, 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); } } finally { buf.release(); @@ -196,7 +202,8 @@ public void onClose(Channel channel) { WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - // FIXME How could this test not succeed, we just checked above that attribute is a NettyResponseFuture???? + // 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)."); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 88357866bd..08e14e6183 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -37,6 +37,8 @@ import org.asynchttpclient.websocket.WebSocketByteListener; import org.asynchttpclient.websocket.WebSocketCloseCodeReasonListener; import org.asynchttpclient.websocket.WebSocketListener; +import org.asynchttpclient.websocket.WebSocketPingListener; +import org.asynchttpclient.websocket.WebSocketPongListener; import org.asynchttpclient.websocket.WebSocketTextFragmentListener; import org.asynchttpclient.websocket.WebSocketTextListener; import org.slf4j.Logger; @@ -300,4 +302,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 4e8d62e1a80890d42810799e580681a0c8e6faa1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:41:47 +0200 Subject: [PATCH 0199/2070] Have a config parameter for websocket max buffer size, close #658 --- .../netty/NettyAsyncHttpProviderConfig.java | 24 ++++++++++++------- .../netty/handler/WebSocketProtocol.java | 2 +- .../providers/netty/ws/NettyWebSocket.java | 18 +++++--------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index 38aa908fa9..2e105d2031 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -43,10 +43,8 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig name, Object value) { @@ -116,17 +114,17 @@ public NettyResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) { } 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); } } - + /** * Allow configuring the Netty's event loop. */ @@ -166,6 +164,8 @@ public NettyWebSocket newNettyWebSocket(Channel channel) { private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + private int webSocketMaxBufferSize = 128000000; + public EventLoopGroup getEventLoopGroup() { return eventLoopGroup; } @@ -293,4 +293,12 @@ public NettyWebSocketFactory getNettyWebSocketFactory() { public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory) { this.nettyWebSocketFactory = nettyWebSocketFactory; } + + public int getWebSocketMaxBufferSize() { + return webSocketMaxBufferSize; + } + + public void setWebSocketMaxBufferSize(int webSocketMaxBufferSize) { + this.webSocketMaxBufferSize = webSocketMaxBufferSize; + } } diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java index 7dfbbe0690..117330693d 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/handler/WebSocketProtocol.java @@ -61,7 +61,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/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index 08e14e6183..d93e3ef8dc 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig; import org.asynchttpclient.providers.netty.response.NettyResponseBodyPart; import org.asynchttpclient.websocket.WebSocket; import org.asynchttpclient.websocket.WebSocketByteFragmentListener; @@ -50,19 +51,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 @@ -107,14 +109,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 e1da1c6c8b77b01cc96fbdb01c3ce63eb1fa664e Mon Sep 17 00:00:00 2001 From: oleksiys Date: Fri, 1 Aug 2014 16:13:14 -0700 Subject: [PATCH 0200/2070] [master] + don't add another Host header if it's already set --- .../filters/AsyncHttpClientFilter.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java index e1d4c8f60f..7d80c95d99 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java @@ -420,15 +420,18 @@ private static FilterChainContext obtainProtocolChainContext(final FilterChainCo return newFilterChainContext; } - private static void addHostHeader(final Request request, final UriComponents uri, final HttpRequestPacket requestPacket) { - String host = request.getVirtualHost(); - if (host != null) { - requestPacket.addHeader(Header.Host, host); - } else { - if (uri.getPort() == -1) { - requestPacket.addHeader(Header.Host, uri.getHost()); + private static void addHostHeader(final Request request, + final UriComponents uri, final HttpRequestPacket requestPacket) { + if (!request.getHeaders().containsKey(Header.Host.toString())) { + String host = request.getVirtualHost(); + if (host != null) { + requestPacket.addHeader(Header.Host, host); } else { - requestPacket.addHeader(Header.Host, uri.getHost() + ':' + uri.getPort()); + if (uri.getPort() == -1) { + requestPacket.addHeader(Header.Host, uri.getHost()); + } else { + requestPacket.addHeader(Header.Host, uri.getHost() + ':' + uri.getPort()); + } } } } From 7d285b5ed15439c376c7ba3c2aa3c89db80274eb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 07:46:20 +0200 Subject: [PATCH 0201/2070] Upgrade Netty 4.0.23.Final, close #667 --- providers/netty/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/pom.xml b/providers/netty/pom.xml index bc9e908b63..57510c4cfc 100644 --- a/providers/netty/pom.xml +++ b/providers/netty/pom.xml @@ -39,7 +39,7 @@ io.netty netty-all - 4.0.20.Final + 4.0.23.Final org.javassist From 550ce1cc02628dadcd5f976c50fce80548064579 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 07:48:21 +0200 Subject: [PATCH 0202/2070] Fix MiscUtils: closeSilently should check for nullity, close #662 --- .../main/java/org/asynchttpclient/util/MiscUtils.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java index 1943f9939b..55b5ba12cd 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtils.java @@ -52,9 +52,10 @@ public static T withDefault(T value, T defaults) { } public static void closeSilently(Closeable closeable) { - try { - closeable.close(); - } catch (IOException e) { - } + if (closeable != null) + try { + closeable.close(); + } catch (IOException e) { + } } } From e33026d481671313fd4c1d35a51c9aa38371e09f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:33:47 +0200 Subject: [PATCH 0203/2070] Append char instead of String --- .../providers/netty/request/NettyRequestFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index bd2850be64..0e24e441a2 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/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 3014f512f2764ceb5b7893684e278fc536867927 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:34:37 +0200 Subject: [PATCH 0204/2070] 0 means empty file, not chunked --- .../providers/netty/request/NettyRequestFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 0e24e441a2..62cf4e89bb 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -280,10 +280,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 babb5be9c7dda2adc2fbf646dff952b48f8802ae Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:36:40 +0200 Subject: [PATCH 0205/2070] Don't use replace but addAfter+remove so that first frame is not lost, close #471 --- .../providers/netty/channel/ChannelManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java index 6fb3b03f3b..43d8aa9bd2 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java @@ -385,8 +385,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) { @@ -416,7 +418,8 @@ public Bootstrap getBootstrap(UriComponents uri, boolean useProxy, boolean useSS } 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 429cc63fc92ae720e0de31df4f77f8b202952869 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:38:55 +0200 Subject: [PATCH 0206/2070] minor clean up --- .../netty/request/NettyRequestFactory.java | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java index 62cf4e89bb..ac3368d5c3 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/request/NettyRequestFactory.java @@ -266,63 +266,65 @@ 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) { - httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - httpRequest.headers().set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey()); - httpRequest.headers().set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); - - } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); + headers.set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET)// + .set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE)// + .set(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort()))// + .set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey())// + .set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); + + } 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 b01e94ffa0b4295ede2950736b5e132bce45f789 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:58:04 +0200 Subject: [PATCH 0207/2070] Target JDK7, use getHostString instead of getHostName, close #672 --- .../asynchttpclient/providers/netty/channel/SslInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java index 31819ee86b..0a938b1f5f 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/SslInitializer.java @@ -41,7 +41,7 @@ public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, Sock throws Exception { InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) remoteAddress; - String peerHost = remoteInetSocketAddress.getHostName(); + String peerHost = remoteInetSocketAddress.getHostString(); int peerPort = remoteInetSocketAddress.getPort(); SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); From 6918cced9415327adf2d636d66d84bb8d604c6fc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:12:35 +0200 Subject: [PATCH 0208/2070] Do not block the WebSocket from receiving bytes or text fragments, close #660 --- .../providers/netty/ws/NettyWebSocket.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java index d93e3ef8dc..3cdb818a50 100755 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/ws/NettyWebSocket.java @@ -179,10 +179,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; } @@ -192,7 +190,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 21660bae880b13b4909a2e018648e3e9723ef2e2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:15:08 +0200 Subject: [PATCH 0209/2070] Wrong javadoc, close #666 --- api/src/main/java/org/asynchttpclient/Request.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/org/asynchttpclient/Request.java b/api/src/main/java/org/asynchttpclient/Request.java index 597931456f..e292e8b5e8 100644 --- a/api/src/main/java/org/asynchttpclient/Request.java +++ b/api/src/main/java/org/asynchttpclient/Request.java @@ -34,7 +34,6 @@ * .setPassword(admin) * .setRealmName("MyRealm") * .setScheme(Realm.AuthScheme.DIGEST).build()); - * r.execute(); * */ public interface Request { From b0ec7416912eeb0ca835bdead850f38c7e6e8851 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 15:04:53 +0200 Subject: [PATCH 0210/2070] Add handler callbacks, close #673 --- .../AsyncHandlerExtensions.java | 24 ++++++++++++++--- .../netty/request/NettyConnectListener.java | 27 ++++++++++--------- .../netty/request/NettyRequestSender.java | 19 +++++++++---- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java index fd4a5bf79e..1d81570b0f 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHandlerExtensions.java @@ -19,7 +19,6 @@ * * More additional hooks might come, such as: *