[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-881?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Tim Boemker updated HTTPCLIENT-881:
-----------------------------------

    Attachment: HTTPCLIENT-881.patch

Also attached.

Index: AbstractClientConnAdapter.java
===================================================================
--- AbstractClientConnAdapter.java      (revision 825665)
+++ AbstractClientConnAdapter.java      (working copy)
@@ -86,6 +86,9 @@
     /** True if the connection has been aborted. */
     private volatile boolean aborted;

+    /** True if the connection has been released. */
+    private boolean released;
+
     /** The duration this is valid for while idle (in ms). */
     private volatile long duration;

@@ -316,16 +319,25 @@
     }

     public void releaseConnection() {
+        synchronized(this) {
+            if (aborted || released) {
+                return;
+            }
+            released = true;
+        }
         if (connManager != null) {
             connManager.releaseConnection(this, duration, 
TimeUnit.MILLISECONDS);
         }
     }

+
     public void abortConnection() {
-        if (aborted) {
-            return;
+        synchronized(this) {
+            if (aborted || released) {
+                return;
+            }
+            aborted = true;
         }
-        aborted = true;
         unmarkReusable();
         try {
             shutdown();





> 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]

Reply via email to