Author: markt Date: Mon Jun 12 18:42:32 2017 New Revision: 1798509 URL: http://svn.apache.org/viewvc?rev=1798509&view=rev Log: Make asynchronous error handling more robust. In particular ensure that onError() is called for any registered AsyncListeners after an I/O error on a non-container thread.
Modified: tomcat/trunk/conf/logging.properties 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/conf/logging.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/conf/logging.properties?rev=1798509&r1=1798508&r2=1798509&view=diff ============================================================================== --- tomcat/trunk/conf/logging.properties (original) +++ tomcat/trunk/conf/logging.properties Mon Jun 12 18:42:32 2017 @@ -65,6 +65,8 @@ org.apache.catalina.core.ContainerBase.[ # To see debug messages for HTTP/2 handling, uncomment the following line: #org.apache.coyote.http2.level = FINE +org.apache.coyote.level = FINEST +org.apache.catalina.level = FINEST # To see debug messages for WebSocket handling, uncomment the following line: #org.apache.tomcat.websocket.level = FINE Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1798509&r1=1798508&r2=1798509&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Mon Jun 12 18:42:32 2017 @@ -95,6 +95,7 @@ public abstract class AbstractProcessor // 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. + asyncStateMachine.asyncMustError(); getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), 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=1798509&r1=1798508&r2=1798509&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] (original) +++ tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] Mon Jun 12 18:42:32 2017 @@ -66,38 +66,49 @@ import org.apache.tomcat.util.security.P * differences required to avoid race conditions during error * handling. * DISPATCHING - The dispatch is being processed. + * MUST_ERROR - ServletRequest.startAsync() has been called followed by an + * I/O error on a non-container thread. The main purpose of + * this state is to prevent additional async actions + * (complete(), dispatch() etc.) on the non-container thread. + * The container will perform the necessary error handling, + * including ensuring that the AsyncLister.onError() method + * is called. * ERROR - Something went wrong. * - * |-----------------»------| - * | \|/ /---«-------------------------------«------------------------------| - * | |----------«-----E R R O R--«-----------------------«-------------------------------| | - * | | complete() /|\/|\\ \-«--------------------------------«-------| | | - * | | | | \ | | | - * | | |-----»-------| | \-----------»----------| | | | - * | | | | |dispatch() | | | - * | | | | \|/ ^ | | - * | | | | |--|timeout() | | | | - * | | | post() | | \|/ | post() | | | - * | | | |---------- | --»DISPATCHED«---------- | --------------COMPLETING«-----| | | - * | | | | | /|\/|\ | | | /|\ /|\ | | | - * | | | | |---»- | ---| | |startAsync() | timeout()|--| | | | | - * | | ^ ^ | | | | | | | ^ | - * | | | | | |-- \ -----| | complete() | |post() | | | - * | | | | | | \ | /--»----- | ---COMPLETE_PENDING-»-| ^ | | - * | | | | | | \ | / | | | | - * | | | | | ^ \ | / | | | | - * | \|/ | | | | \ \|/ / post() | complete() | | | - * | MUST_COMPLETE-«- | - | --«----STARTING--»--------- | ------------| /---»-----| | | - * | /|\ /|\ | | complete() | \ | | / | ^ - * | | | | | | \ | post() | / error() | | - * | | | ^ | dispatch()| \ | |-----| | //------»-------| | - * | | | | | | \ | | | | // | - * | | | | | \|/ \ | | \|/\|/ // post() | + * |-----«-------------------------------«------------------------------| + * | | + * | error() | + * |-----------------»---| | |--«--------MUST_ERROR---------------«------------------------| | + * | \|/ \|/\|/ | | + * | |----------«-----E R R O R--«-----------------------«-------------------------------| | | + * | | complete() /|\/|\\ \-«--------------------------------«-------| | | | + * | | | | \ | | | | + * | | |-----»-------| | \-----------»----------| | | | | + * | | | | |dispatch() | | ^ | + * | | | | \|/ ^ | | | + * | | | | |--|timeout() | | | | | + * | | | post() | | \|/ | post() | | | | + * | | | |---------- | --»DISPATCHED«---------- | --------------COMPLETING«-----| | | | + * | | | | | /|\/|\ | | | /|\ /|\ | | | | + * | | | | |---»- | ---| | |startAsync() | timeout()|--| | | | | | + * | | ^ ^ | | | | | | | ^ | | + * | | | | | |-- \ -----| | complete() | |post() | | | | + * | | | | | | \ | /--»----- | ---COMPLETE_PENDING-»-| ^ | | | + * | | | | | | \ | / | | | | | + * | | | | | ^ \ | / | complete() | | | | + * | \|/ | | | | \ \|/ / post() | /---»-----| | ^ | + * | MUST_COMPLETE-«- | - | --«----STARTING--»--------- | ------------| / | | | + * | /|\ /|\ | | complete() | \ | | / error() | | ^ + * | | | | | | \ | | //---»----------| | | + * | | | ^ | dispatch()| \ | post() | // | | + * | | | | | | \ | |-----| | // nct-io-error | | + * | | | | | | \ | | | | ///---»---------------| | + * | | | | | \|/ \ | | \|/\| ||| | * | | | | |--«--MUST_DISPATCH-----«-----| |--«--STARTED«---------«---------| | - * | | | | dispatched() /|\ | \ / | | | | - * | | | | | | \ / | | | | - * | | | | | | \ / | | | | - * | | | | | |post() \ | | | ^ | + * | | | | dispatched() /|\ | \ / | | post() | | + * | | | | | | \ / | | | | + * | | | | | | \ / | | | | + * | | | | | |post() | | | | ^ | * ^ | ^ | | | \|/ | | |asyncOperation() | | * | | | ^ | | DISPATCH_PENDING | | | | | * | | | | | | |post() | | | | | @@ -142,6 +153,7 @@ public class AsyncStateMachine { DISPATCH_PENDING(true, true, false, false), DISPATCHING (true, false, false, true), READ_WRITE_OP (true, true, false, false), + MUST_ERROR (true, true, false, false), ERROR (true, true, false, false); private final boolean isAsync; @@ -384,6 +396,18 @@ public class AsyncStateMachine { } + public synchronized void asyncMustError() { + if (state == AsyncState.STARTED) { + clearNonBlockingListeners(); + state = AsyncState.MUST_ERROR; + } else { + throw new IllegalStateException( + sm.getString("asyncStateMachine.invalidAsyncState", + "asyncMustError()", state)); + } + } + + public synchronized void asyncError() { if (state == AsyncState.STARTING || state == AsyncState.STARTED || @@ -391,7 +415,8 @@ public class AsyncStateMachine { state == AsyncState.TIMING_OUT || state == AsyncState.MUST_COMPLETE || state == AsyncState.READ_WRITE_OP || - state == AsyncState.COMPLETING) { + state == AsyncState.COMPLETING || + state == AsyncState.MUST_ERROR) { 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=1798509&r1=1798508&r2=1798509&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Mon Jun 12 18:42:32 2017 @@ -117,6 +117,12 @@ changed the status code recorded in the access log when the client dropped the connection from 200 to 500. (markt) </fix> + <fix> + Make asynchronous error handling more robust. In particular ensure that + <code>onError()</code> is called for any registered + <code>AsyncListener</code>s after an I/O error on a non-container + thread. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org