[
https://issues.apache.org/jira/browse/HTTPCLIENT-881?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12766630#action_12766630
]
Tim Boemker commented on HTTPCLIENT-881:
----------------------------------------
With the latest changes, I'm able to get HttpClient.execute to throw an
IllegalStateException.
Steps to reproduce:
1) Run one thread to line 385 in DefaultRequestDirector, where it calls
establishRoute.
2) Run a second thread that calls HttpUriRequest.abort. Abort calls
BasicPooledConnAdapter.abortConnection, which calls
ThreadSafeClientConnManager.releaseConnection, which calls
BasicPooledConnAdapter.detach.
3) Let the main thread continue. It throws an IllegalStateException because the
adapter is now detached:
java.lang.IllegalStateException: Adapter is detached.
at
org.apache.http.impl.conn.AbstractPooledConnAdapter.assertAttached(AbstractPooledConnAdapter.java:75)
at
org.apache.http.impl.conn.AbstractPooledConnAdapter.getRoute(AbstractPooledConnAdapter.java:91)
at
org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:641)
at
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:385)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:674)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:609)
> AbstractClientConnAdapter doesn't ensure that only one of
> ConnectionReleaseTrigger.abortConnection, .releaseConnection has effect
> ---------------------------------------------------------------------------------------------------------------------------------
>
> Key: HTTPCLIENT-881
> URL: https://issues.apache.org/jira/browse/HTTPCLIENT-881
> Project: HttpComponents HttpClient
> Issue Type: Bug
> Components: HttpConn
> Affects Versions: 4.0 Final
> Reporter: Tim Boemker
> Fix For: 4.1 Alpha1
>
> Attachments: HTTPCLIENT-881.patch
>
>
> If HttpUriRequest.abort() is called at about the same time that the request
> completes, it's possible for an aborted connection to be returned to the
> pool. The next time the connection is used, HttpClient.execute fails without
> retrying, throwing this exception:
> java.io.IOException: Connection already shutdown
> at
> org.apache.http.impl.conn.DefaultClientConnection.opening(DefaultClientConnection.java:112)
> at
> org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:120)
> at
> org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147)
> at
> org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:101)
> at
> org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:381)
> at
> org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
> at
> org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
> Steps to reproduce:
> 1) Set a breakpoint in ThreadSafeClientConnManager.releaseConnection just
> after "reusable" is set (and found to be true).
> 2) Run to the breakpoint in releaseConnection.
> 3) Call HttpUriRequest.abort.
> 4) Let releaseConnection complete.
> When the connection is next used, the exception will be thrown.
> Snippet from ThreadSafeClientConnManager:
> public void releaseConnection(ManagedClientConnection conn, long
> validDuration, TimeUnit timeUnit) {
> ...
> boolean reusable = hca.isMarkedReusable();
> if (log.isDebugEnabled()) { //
> breakpoint here
> if (reusable) {
> log.debug("Released connection is reusable.");
> } else {
> log.debug("Released connection is not reusable.");
> }
> }
> hca.detach();
> if (entry != null) {
> connectionPool.freeEntry(entry, reusable, validDuration,
> timeUnit);
> }
> }
> }
> I think that AbstractClientConnAdapter should be modified as follows:
> 1) Add "released" flag:
> /** True if the connection has been released. */
> private boolean released;
> 2) Modify abortConnection:
> public void abortConnection() {
> synchronized(this) {
> if (aborted || released) {
> return;
> }
> aborted = true;
> }
> unmarkReusable(); // this line and all that follow unchanged
> 3) Modify releaseConnection:
> public void releaseConnection() {
> synchronized(this) {
> if (aborted || released) {
> return;
> }
> released = true;
> }
> if (connManager != null) {
> connManager.releaseConnection(this, duration,
> TimeUnit.MILLISECONDS);
> }
> }
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]