HTTPCLIENT-881: Fixed race condition in AbstractClientConnAdapter that makes it possible for an aborted connection to be returned to the pool

Contributed by Tim Boemker <tboemker at elynx.com>

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@825864 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2009-10-16 12:22:27 +00:00
parent 0b815c2505
commit 4b422e1733
2 changed files with 16 additions and 8 deletions

View File

@ -1,6 +1,11 @@
Changes since 4.0 Changes since 4.0
------------------- -------------------
* [HTTPCLIENT-881] Fixed race condition in AbstractClientConnAdapter that makes it
possible for an aborted connection to be returned to the pool.
Contributed by Tim Boemker <tboemker at elynx.com> and
Oleg Kalnichevski <olegk at apache.org>
* [HTTPCLIENT-832] Distinguish cookie format errors from violations of restrictions * [HTTPCLIENT-832] Distinguish cookie format errors from violations of restrictions
imposed by a cookie specification. In the latter case imposed by a cookie specification. In the latter case
CookieRestrictionViolationException will be thrown. CookieRestrictionViolationException will be thrown.

View File

@ -83,8 +83,8 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
/** The reusability marker. */ /** The reusability marker. */
private volatile boolean markedReusable; private volatile boolean markedReusable;
/** True if the connection has been aborted. */ /** True if the connection has been shut down or released. */
private volatile boolean aborted; private volatile boolean shutdown;
/** The duration this is valid for while idle (in ms). */ /** The duration this is valid for while idle (in ms). */
private volatile long duration; private volatile long duration;
@ -104,7 +104,7 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
connManager = mgr; connManager = mgr;
wrappedConnection = conn; wrappedConnection = conn;
markedReusable = false; markedReusable = false;
aborted = false; shutdown = false;
duration = Long.MAX_VALUE; duration = Long.MAX_VALUE;
} // <constructor> } // <constructor>
@ -133,7 +133,7 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
* @throws InterruptedIOException if the connection has been aborted * @throws InterruptedIOException if the connection has been aborted
*/ */
protected final void assertNotAborted() throws InterruptedIOException { protected final void assertNotAborted() throws InterruptedIOException {
if (aborted) { if (shutdown) {
throw new InterruptedIOException("Connection has been shut down."); throw new InterruptedIOException("Connection has been shut down.");
} }
} }
@ -160,7 +160,7 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
} }
public boolean isStale() { public boolean isStale() {
if (aborted) if (shutdown)
return true; return true;
OperatedClientConnection conn = getWrappedConnection(); OperatedClientConnection conn = getWrappedConnection();
if (conn == null) if (conn == null)
@ -316,16 +316,17 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
} }
public void releaseConnection() { public void releaseConnection() {
shutdown = true;
if (connManager != null) { if (connManager != null) {
connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS); connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
} }
} }
public void abortConnection() { public void abortConnection() {
if (aborted) { if (shutdown) {
return; return;
} }
aborted = true; shutdown = true;
unmarkReusable(); unmarkReusable();
try { try {
shutdown(); shutdown();
@ -345,7 +346,9 @@ public abstract class AbstractClientConnAdapter implements ManagedClientConnecti
// manager if #abortConnection() is called from the main execution // manager if #abortConnection() is called from the main execution
// thread while there is no blocking I/O operation. // thread while there is no blocking I/O operation.
if (executionThread.equals(Thread.currentThread())) { if (executionThread.equals(Thread.currentThread())) {
releaseConnection(); if (connManager != null) {
connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
}
} }
} }