Fixed potential race condition in case of abnormal termination of pipelined message exchange (request producers / response consumers may be not fully closed out)
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpasyncclient/trunk@1631168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractClientExchangeHandler.java b/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractClientExchangeHandler.java
index 0d22b85..c437c40 100644
--- a/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractClientExchangeHandler.java
+++ b/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/AbstractClientExchangeHandler.java
@@ -402,13 +402,16 @@
@Override
public final void failed(final Exception ex) {
- try {
- executionFailed(ex);
- } finally {
+ if (this.closed.compareAndSet(false, true)) {
try {
- this.resultFuture.failed(ex);
+ try {
+ executionFailed(ex);
+ } finally {
+ discardConnection();
+ releaseResources();
+ }
} finally {
- close();
+ this.resultFuture.failed(ex);
}
}
}
@@ -423,11 +426,11 @@
try {
return executionCancelled();
} finally {
- this.resultFuture.cancel();
+ discardConnection();
+ releaseResources();
}
} finally {
- discardConnection();
- releaseResources();
+ this.resultFuture.cancel();
}
}
return false;
diff --git a/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/PipeliningClientExchangeHandlerImpl.java b/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/PipeliningClientExchangeHandlerImpl.java
index 994c9a9..8b06a38 100644
--- a/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/PipeliningClientExchangeHandlerImpl.java
+++ b/httpasyncclient/src/main/java/org/apache/http/impl/nio/client/PipeliningClientExchangeHandlerImpl.java
@@ -153,6 +153,9 @@
if (responseConsumer != null) {
responseConsumer.failed(ex);
}
+ for (final HttpAsyncResponseConsumer<T> cancellable: this.responseConsumerQueue) {
+ cancellable.cancel();
+ }
}
@Override
@@ -296,7 +299,7 @@
if (result != null) {
this.resultQueue.add(result);
} else {
- this.resultFuture.failed(ex);
+ failed(ex);
}
if (!this.resultFuture.isDone() && this.responseConsumerQueue.isEmpty()) {
this.resultFuture.completed(new ArrayList<T>(this.resultQueue));
diff --git a/httpasyncclient/src/test/java/org/apache/http/nio/client/integration/TestHttpAsyncPipelining.java b/httpasyncclient/src/test/java/org/apache/http/nio/client/integration/TestHttpAsyncPipelining.java
index c13b699..80830d7 100644
--- a/httpasyncclient/src/test/java/org/apache/http/nio/client/integration/TestHttpAsyncPipelining.java
+++ b/httpasyncclient/src/test/java/org/apache/http/nio/client/integration/TestHttpAsyncPipelining.java
@@ -216,9 +216,9 @@
Assert.assertNotNull(c1.getResult());
Assert.assertTrue(c2.isDone());
Assert.assertNotNull(c2.getResult());
- Assert.assertFalse(c3.isDone());
+ Assert.assertTrue(c3.isDone());
Assert.assertNull(c3.getResult());
- Assert.assertFalse(c4.isDone());
+ Assert.assertTrue(c4.isDone());
Assert.assertNull(c4.getResult());
}