Skip to content

Commit 39327bd

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 11bbab9 + 8ec5d98 commit 39327bd

File tree

5 files changed

+101
-103
lines changed

5 files changed

+101
-103
lines changed

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
<configuration>
199199
<manifestLocation>META-INF</manifestLocation>
200200
<instructions>
201+
<Bundle-Version>$(replace;$(project.version);-SNAPSHOT;.$(tstamp;yyyyMMdd-HHmm))</Bundle-Version>
201202
<Bundle-Vendor>Sonatype</Bundle-Vendor>
202203
<Import-Package>
203204
org.jboss.netty.*;resolution:=optional,
@@ -206,7 +207,7 @@
206207
*
207208
</Import-Package>
208209
<Export-Package>
209-
com.ning.http.*;version="1.6.1"
210+
com.ning.http.*;version="$(replace;$(project.version);-SNAPSHOT;"")"
210211
</Export-Package>
211212
</instructions>
212213
</configuration>

src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java

Lines changed: 41 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -720,14 +720,14 @@ public Response prepareResponse(final HttpResponseStatus status,
720720
/* @Override */
721721

722722
public <T> ListenableFuture<T> execute(Request request, final AsyncHandler<T> asyncHandler) throws IOException {
723-
return doConnect(request, asyncHandler, null, true);
723+
return doConnect(request, asyncHandler, null, true, executeConnectAsync);
724724
}
725725

726-
private <T> void execute(final Request request, final NettyResponseFuture<T> f, boolean useCache) throws IOException {
727-
doConnect(request, f.getAsyncHandler(), f, useCache);
726+
private <T> void execute(final Request request, final NettyResponseFuture<T> f, boolean useCache, boolean asyncConnect) throws IOException {
727+
doConnect(request, f.getAsyncHandler(), f, useCache, asyncConnect);
728728
}
729729

730-
private <T> ListenableFuture<T> doConnect(final Request request, final AsyncHandler<T> asyncHandler, NettyResponseFuture<T> f, boolean useCache) throws IOException {
730+
private <T> ListenableFuture<T> doConnect(final Request request, final AsyncHandler<T> asyncHandler, NettyResponseFuture<T> f, boolean useCache, boolean asyncConnect) throws IOException {
731731

732732
if (isClose.get()) {
733733
throw new IOException("Closed");
@@ -827,7 +827,7 @@ private <T> ListenableFuture<T> doConnect(final Request request, final AsyncHand
827827
directInvokation = false;
828828
}
829829

830-
if (directInvokation && !executeConnectAsync && request.getFile() == null) {
830+
if (directInvokation && !asyncConnect && request.getFile() == null) {
831831
int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE;
832832
if (!channelFuture.awaitUninterruptibly(timeOut, TimeUnit.MILLISECONDS)) {
833833
abort(c.future(), new ConnectException("Connect times out"));
@@ -906,7 +906,6 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr
906906
HttpChunk chunk = (HttpChunk) e.getMessage();
907907
if (chunk.isLast()) {
908908
AsyncCallable ac = (AsyncCallable) ctx.getAttachment();
909-
ctx.setAttachment(ac.future());
910909
ac.call();
911910
}
912911
return;
@@ -1049,17 +1048,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr
10491048
future.attachChannel(ctx.getChannel(), true);
10501049
}
10511050

1052-
// We must consume the body first in order to re-use the connection.
1053-
if (response.isChunked()) {
1054-
ctx.setAttachment(new AsyncCallable(future) {
1055-
public Object call() throws Exception {
1056-
nextRequest(builder.setHeaders(headers).setRealm(nr).build(), future);
1057-
return null;
1058-
}
1059-
});
1060-
} else {
1061-
nextRequest(builder.setHeaders(headers).setRealm(nr).build(), future);
1062-
}
1051+
nextRequest(builder.setHeaders(headers).setRealm(nr).build(), future);
10631052
return;
10641053
}
10651054

@@ -1078,16 +1067,7 @@ public Object call() throws Exception {
10781067

10791068
log.debug("Sending proxy authentication to {}", request.getUrl());
10801069

1081-
if (response.isChunked()) {
1082-
ctx.setAttachment(new AsyncCallable(future) {
1083-
public Object call() throws Exception {
1084-
nextRequest(future.getRequest(), future);
1085-
return null;
1086-
}
1087-
});
1088-
} else {
1089-
nextRequest(future.getRequest(), future);
1090-
}
1070+
nextRequest(future.getRequest(), future);
10911071
return;
10921072
}
10931073

@@ -1125,36 +1105,18 @@ public Object call() throws Exception {
11251105
if (!uri.toString().equalsIgnoreCase(future.getURI().toString())) {
11261106
final RequestBuilder builder = new RequestBuilder(future.getRequest());
11271107
final URI initialConnectionUri = future.getURI();
1128-
final boolean initialConnectionKeepAlive = future.getKeepAlive();
11291108
future.setURI(uri);
11301109
final String newUrl = uri.toString();
11311110

11321111
log.debug("Redirecting to {}", newUrl);
11331112

11341113
if (response.isChunked()) {
1135-
ctx.setAttachment(new AsyncCallable(future) {
1136-
public Object call() throws Exception {
1137-
if (initialConnectionKeepAlive) {
1138-
if (!connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(initialConnectionUri), ctx.getChannel())) {
1139-
finishChannel(ctx);
1140-
}
1141-
} else {
1142-
closeChannel(ctx);
1143-
}
1144-
nextRequest(builder.setUrl(newUrl).build(), future);
1145-
return null;
1146-
}
1147-
});
1114+
drainChannel(ctx, future, initialConnectionUri);
11481115
} else {
1149-
if (initialConnectionKeepAlive) {
1150-
if (!connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(initialConnectionUri), ctx.getChannel())) {
1151-
finishChannel(ctx);
1152-
}
1153-
} else {
1154-
closeChannel(ctx);
1155-
}
1156-
nextRequest(builder.setUrl(newUrl).build(), future);
1116+
closeChannel(ctx);
11571117
}
1118+
1119+
nextRequest(builder.setUrl(newUrl).build(), future);
11581120
return;
11591121
}
11601122
} else {
@@ -1179,7 +1141,9 @@ public Object call() throws Exception {
11791141

11801142
if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) {
11811143
updateBodyAndInterrupt(handler, new ResponseBodyPart(future.getURI(), response, this));
1182-
markAsDoneAndCacheConnection(future, ctx, ctx.getChannel().isReadable());
1144+
markAsDoneAndCacheConnection(future, ctx);
1145+
drainChannel(ctx, future, future.getURI());
1146+
return;
11831147
}
11841148

11851149
} else if (e.getMessage() instanceof HttpChunk) {
@@ -1216,6 +1180,21 @@ public Object call() throws Exception {
12161180
}
12171181
}
12181182

1183+
private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture<?> future, final URI uri){
1184+
ctx.setAttachment(new AsyncCallable(future) {
1185+
public Object call() throws Exception {
1186+
if (future.getKeepAlive() && ctx.getChannel().isReadable()) {
1187+
if (!connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(uri), ctx.getChannel())) {
1188+
finishChannel(ctx);
1189+
}
1190+
} else {
1191+
finishChannel(ctx);
1192+
}
1193+
return null;
1194+
}
1195+
});
1196+
}
1197+
12191198
private FilterContext handleIoException(FilterContext fc, NettyResponseFuture<?> future) {
12201199
for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) {
12211200
try {
@@ -1237,18 +1216,8 @@ private void replayRequest(final NettyResponseFuture<?> future, FilterContext fc
12371216
future.touch();
12381217

12391218
log.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future);
1240-
1241-
// We must consume the body first in order to re-use the connection.
1242-
if (response != null && response.isChunked()) {
1243-
ctx.setAttachment(new AsyncCallable(future) {
1244-
public Object call() throws Exception {
1245-
nextRequest(newRequest, future);
1246-
return null;
1247-
}
1248-
});
1249-
} else {
1250-
nextRequest(newRequest, future);
1251-
}
1219+
drainChannel(ctx, future, future.getURI());
1220+
nextRequest(newRequest, future);
12521221
return;
12531222
}
12541223

@@ -1267,7 +1236,7 @@ private void nextRequest(final Request request, final NettyResponseFuture<?> fut
12671236
}
12681237

12691238
private void nextRequest(final Request request, final NettyResponseFuture<?> future, final boolean useCache) throws IOException {
1270-
execute(request, future, useCache);
1239+
execute(request, future, useCache, true);
12711240
}
12721241

12731242
private void abort(NettyResponseFuture<?> future, Throwable t) {
@@ -1386,20 +1355,10 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture<?> future)
13861355
return false;
13871356
}
13881357

1389-
private void markAsDoneAndCacheConnection(final NettyResponseFuture<?> future, final ChannelHandlerContext ctx,
1390-
final boolean cache) throws MalformedURLException {
1358+
private void markAsDoneAndCacheConnection(final NettyResponseFuture<?> future, final ChannelHandlerContext ctx) throws MalformedURLException {
13911359
// We need to make sure everything is OK before adding the connection back to the pool.
13921360
try {
1393-
future.done(new Callable<Boolean>() {
1394-
public Boolean call() throws Exception {
1395-
if (future.getKeepAlive() && cache) {
1396-
if (!connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(future.getURI()), ctx.getChannel())) {
1397-
finishChannel(ctx);
1398-
}
1399-
}
1400-
return false;
1401-
}
1402-
});
1361+
future.done(null);
14031362
} catch (Throwable t) {
14041363
// Never propagate exception once we know we are done.
14051364
log.debug(t.getMessage(), t);
@@ -1412,15 +1371,15 @@ public Boolean call() throws Exception {
14121371

14131372
private void finishUpdate(final NettyResponseFuture<?> future, final ChannelHandlerContext ctx, boolean isChunked) throws IOException {
14141373
if (isChunked && future.getKeepAlive()) {
1415-
ctx.setAttachment(new AsyncCallable(future) {
1416-
public Object call() throws Exception {
1417-
markAsDoneAndCacheConnection(future, ctx, ctx.getChannel().isReadable());
1418-
return null;
1419-
}
1420-
});
1374+
drainChannel(ctx, future, future.getURI());
14211375
} else {
1422-
markAsDoneAndCacheConnection(future, ctx, markChannelNotReadable(ctx));
1376+
if (future.getKeepAlive() && ctx.getChannel().isReadable()) {
1377+
if (!connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(future.getURI()), ctx.getChannel())) {
1378+
finishChannel(ctx);
1379+
}
1380+
}
14231381
}
1382+
markAsDoneAndCacheConnection(future, ctx);
14241383
}
14251384

14261385
private boolean markChannelNotReadable(final ChannelHandlerContext ctx) {

src/main/java/com/ning/http/multipart/Part.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* This class is an adaptation of the Apache HttpClient implementation
2424
* @link http://hc.apache.org/httpclient-3.x/
2525
*/
26-
public abstract class Part {
26+
public abstract class Part implements com.ning.http.client.Part {
2727

2828
/**
2929
* The boundary

src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ public final static MultipartRequestEntity createMultipartRequestEntity(List<Par
194194
int i = 0;
195195

196196
for (Part part : params) {
197-
if (part instanceof StringPart) {
197+
if (part instanceof com.ning.http.multipart.Part) {
198+
parts[i] = (com.ning.http.multipart.Part) part;
199+
} else if (part instanceof StringPart) {
198200
parts[i] = new com.ning.http.multipart.StringPart(part.getName(),
199201
((StringPart) part).getValue(),
200202
"UTF-8");

src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.testng.annotations.BeforeMethod;
2828
import org.testng.annotations.Test;
2929

30-
3130
import javax.servlet.ServletException;
3231
import javax.servlet.http.HttpServlet;
3332
import javax.servlet.http.HttpServletRequest;
@@ -106,7 +105,7 @@ public void stop() {
106105
}
107106

108107
private ListenableFuture<Response> testMethodRequest(AsyncHttpClient
109-
fetcher, int requests,String action, String id) throws IOException {
108+
fetcher, int requests, String action, String id) throws IOException {
110109
RequestBuilder builder = new RequestBuilder("GET");
111110
builder.addQueryParameter(action, "1");
112111

@@ -137,7 +136,7 @@ public void testRetryNonBlocking() throws IOException, InterruptedException,
137136

138137
bc.setAllowPoolingConnection(true);
139138
bc.setMaximumConnectionsTotal(100);
140-
bc.setConnectionTimeoutInMs(30000);
139+
bc.setConnectionTimeoutInMs(60000);
141140
bc.setRequestTimeoutInMs(30000);
142141

143142
NettyAsyncHttpProviderConfig config = new
@@ -146,13 +145,54 @@ public void testRetryNonBlocking() throws IOException, InterruptedException,
146145
bc.setAsyncHttpClientProviderConfig(config);
147146
c = new AsyncHttpClient(bc.build());
148147

149-
res.add(testMethodRequest(c,
150-
3, "servlet", UUID.randomUUID().toString()));
151-
res.add(testMethodRequest(c, 3, "io", UUID.randomUUID().toString()));
152-
res.add(testMethodRequest(c,
153-
3, "normal", UUID.randomUUID().toString()));
154-
res.add(testMethodRequest(c, 3, "500", UUID.randomUUID().toString()));
155-
res.add(testMethodRequest(c, 3, "500", UUID.randomUUID().toString()));
148+
for (int i = 0; i < 32; i++) {
149+
res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString()));
150+
}
151+
152+
StringBuilder b = new StringBuilder();
153+
for (ListenableFuture<Response> r : res) {
154+
Response theres = r.get();
155+
b.append("==============\r\n");
156+
b.append("Response Headers\r\n");
157+
Map<String, List<String>> heads = theres.getHeaders();
158+
b.append(heads + "\r\n");
159+
b.append("==============\r\n");
160+
assertTrue(heads.size() > 0);
161+
}
162+
System.out.println(b.toString());
163+
System.out.flush();
164+
165+
}
166+
finally {
167+
if (c != null) c.close();
168+
}
169+
}
170+
171+
@Test
172+
public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedException,
173+
ExecutionException {
174+
AsyncHttpClient c = null;
175+
List<ListenableFuture<Response>> res = new
176+
ArrayList<ListenableFuture<Response>>();
177+
try {
178+
AsyncHttpClientConfig.Builder bc =
179+
new AsyncHttpClientConfig.Builder();
180+
181+
bc.setAllowPoolingConnection(true);
182+
bc.setMaximumConnectionsTotal(100);
183+
bc.setConnectionTimeoutInMs(60000);
184+
bc.setRequestTimeoutInMs(30000);
185+
186+
NettyAsyncHttpProviderConfig config = new
187+
NettyAsyncHttpProviderConfig();
188+
config.addProperty(NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT, "true");
189+
190+
bc.setAsyncHttpClientProviderConfig(config);
191+
c = new AsyncHttpClient(bc.build());
192+
193+
for (int i = 0; i < 32; i++) {
194+
res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString()));
195+
}
156196

157197
StringBuilder b = new StringBuilder();
158198
for (ListenableFuture<Response> r : res) {
@@ -191,17 +231,13 @@ public void testRetryBlocking() throws IOException, InterruptedException,
191231
NettyAsyncHttpProviderConfig config = new
192232
NettyAsyncHttpProviderConfig();
193233
config.addProperty(NettyAsyncHttpProviderConfig.USE_BLOCKING_IO, "true");
194-
234+
195235
bc.setAsyncHttpClientProviderConfig(config);
196236
c = new AsyncHttpClient(bc.build());
197237

198-
res.add(testMethodRequest(c,
199-
3, "servlet", UUID.randomUUID().toString()));
200-
res.add(testMethodRequest(c, 3, "io", UUID.randomUUID().toString()));
201-
res.add(testMethodRequest(c,
202-
3, "normal", UUID.randomUUID().toString()));
203-
res.add(testMethodRequest(c, 3, "500", UUID.randomUUID().toString()));
204-
res.add(testMethodRequest(c, 3, "500", UUID.randomUUID().toString()));
238+
for (int i = 0; i < 32; i++) {
239+
res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString()));
240+
}
205241

206242
StringBuilder b = new StringBuilder();
207243
for (ListenableFuture<Response> r : res) {

0 commit comments

Comments
 (0)