Author: markt
Date: Wed Feb 15 20:27:21 2017
New Revision: 1783144

URL: http://svn.apache.org/viewvc?rev=1783144&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=60718
Improve error handling for asynchronous processing and correct a number of 
cases where the <requestDestroyed() event was not being fired and an entry 
wasn't being made in the access logs.

Modified:
    tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
    tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
    tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java
    tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
    tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Wed Feb 
15 20:27:21 2017
@@ -140,14 +140,7 @@ public class CoyoteAdapter implements Ad
         
req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
         try {
             if (!request.isAsync()) {
-                // Error or timeout - need to tell listeners the request is 
over
-                // Have to test this first since state may change while in this
-                // method and this is only required if entering this method in
-                // this state
-                Context ctxt = request.getMappingData().context;
-                if (ctxt != null) {
-                    ctxt.fireRequestDestroyEvent(request);
-                }
+                // Error or timeout
                 // Lift any suspension (e.g. if sendError() was used by an 
async
                 // request) to allow the response to be written to the client
                 response.setSuspended(false);
@@ -382,6 +375,17 @@ public class CoyoteAdapter implements Ad
         } catch (IOException e) {
             // Ignore
         } finally {
+            AtomicBoolean error = new AtomicBoolean(false);
+            res.action(ActionCode.IS_ERROR, error);
+
+            if (request.isAsyncCompleting() && error.get()) {
+                // Connection will be forcibly closed which will prevent
+                // completion happening at the usual point. Need to trigger
+                // call to onComplete() here.
+                res.action(ActionCode.ASYNC_POST_PROCESS,  null);
+                async = false;
+            }
+
             // Access log
             if (!async && postParseSuccess) {
                 // Log only if processing was invoked.
@@ -391,11 +395,9 @@ public class CoyoteAdapter implements Ad
             }
 
             req.getRequestProcessor().setWorkerThreadName(null);
-            AtomicBoolean error = new AtomicBoolean(false);
-            res.action(ActionCode.IS_ERROR, error);
 
             // Recycle the wrapper request and response
-            if (!async || error.get()) {
+            if (!async) {
                 request.recycle();
                 response.recycle();
             }

Modified: tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/AsyncContextImpl.java Wed Feb 15 
20:27:21 2017
@@ -111,6 +111,7 @@ public class AsyncContextImpl implements
                 }
             }
         } finally {
+            context.fireRequestDestroyEvent(request);
             clearServletRequestResponse();
             context.unbind(Globals.IS_SECURITY_ENABLED, oldCL);
         }

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardHostValve.java Wed Feb 
15 20:27:21 2017
@@ -178,7 +178,7 @@ final class StandardHostValve extends Va
                 }
             }
 
-            if (!request.isAsync() && (!asyncAtStart || 
!response.isErrorReportRequired())) {
+            if (!request.isAsync() && !asyncAtStart) {
                 context.fireRequestDestroyEvent(request);
             }
         } finally {

Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Wed Feb 15 
20:27:21 2017
@@ -80,19 +80,19 @@ public abstract class AbstractProcessor
     protected void setErrorState(ErrorState errorState, Throwable t) {
         boolean blockIo = this.errorState.isIoAllowed() && 
!errorState.isIoAllowed();
         this.errorState = this.errorState.getMostSevere(errorState);
+        if (response.getStatus() < 400) {
+            response.setStatus(500);
+        }
+        if (t != null) {
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
+        }
         if (blockIo && !ContainerThreadMarker.isContainerThread() && 
isAsync()) {
             // The error occurred on a non-container thread during async
             // processing which means not all of the necessary clean-up will
             // have been completed. Dispatch to a container thread to do the
             // clean-up. Need to do it this way to ensure that all the 
necessary
             // clean-up is performed.
-            if (response.getStatus() < 400) {
-                response.setStatus(500);
-            }
             
getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t);
-            // Set the request attribute so that the async onError() event is
-            // fired when the error event is processed
-            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
             processSocketEvent(SocketEvent.ERROR, true);
         }
     }

Modified: tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] 
(original)
+++ tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] Wed Feb 
15 20:27:21 2017
@@ -69,15 +69,15 @@ import org.apache.tomcat.util.security.P
  * ERROR            - Something went wrong.
  *
  * |-----------------»------|
- * |                       \|/ 
/-----------------------------------«------------------------------|
- * |   
|----------«-------ERROR----------------------------«-------------------------------|
      |
- * |   |      complete() /|\/|\\                                               
            |      |
- * |   |                  |  |  \                                              
            |      |
- * |   |    |-----»-------|  |   \-----------»----------|                      
            |      |
- * |   |    |                |                          |dispatch()            
            |      |
- * |   |    |                |                         \|/                     
            |      |
- * |   |    |                |          |--|timeout()   |                      
            |      |
- * |   |    |     post()     |          | \|/           |     post()           
            |      |
+ * |                       \|/ 
/---«-------------------------------«------------------------------|
+ * |   |----------«-----E R R O 
R--«-----------------------«-------------------------------|      |
+ * |   |      complete() /|\/|\\ \-«--------------------------------«-------|  
            |      |
+ * |   |                  |  |  \                                           |  
            |      |
+ * |   |    |-----»-------|  |   \-----------»----------|                   |  
            |      |
+ * |   |    |                |                          |dispatch()         |  
            |      |
+ * |   |    |                |                         \|/                  ^  
            |      |
+ * |   |    |                |          |--|timeout()   |                   |  
            |      |
+ * |   |    |     post()     |          | \|/           |     post()        |  
            |      |
  * |   |    |    |---------- | --»DISPATCHED«---------- | 
--------------COMPLETING«-----|  |      |
  * |   |    |    |           |   /|\/|\ |               |                | /|\ 
/|\      |  |      |
  * |   |    |    |    |---»- | ---|  |  |startAsync()   |       timeout()|--|  
 |       |  |      |
@@ -390,7 +390,8 @@ public class AsyncStateMachine {
                 state == AsyncState.DISPATCHED ||
                 state == AsyncState.TIMING_OUT ||
                 state == AsyncState.MUST_COMPLETE ||
-                state == AsyncState.READ_WRITE_OP) {
+                state == AsyncState.READ_WRITE_OP ||
+                state == AsyncState.COMPLETING) {
             clearNonBlockingListeners();
             state = AsyncState.ERROR;
         } else {

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1783144&r1=1783143&r2=1783144&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Feb 15 20:27:21 2017
@@ -89,6 +89,12 @@
         does not include TRACE in the returned Allow header. (markt)
       </fix>
       <fix>
+        <bug>60718</bug>: Improve error handling for asynchronous processing 
and
+        correct a number of cases where the <code>requestDestroyed()</code>
+        event was not being fired and an entry wasn't being made in the access
+        logs. (markt)
+      </fix>
+      <fix>
         <bug>60720</bug>: Replace "WWW-Authenticate" literal with static final
         AUTH_HEADER_NAME in SpnegoAuthenticator. Patch provided by Michael
         Osipov. (violetagg)



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to