Bug 50308 - Call to AsyncContext.dispatch() in the onTimeout callback throws exception
Call to AsyncContext.dispatch() in the onTimeout callback throws exception
Product: Tomcat 7
Classification: Unclassified
Component: Catalina
PC All
: P2 critical with 1 vote (vote)
: ---
Assigned To: Tomcat Developers Mailing List
Depends on:
  Show dependency tree
Reported: 2010-11-20 11:00 UTC by Juriy
Modified: 2010-11-22 09:37 UTC (History)
1 user (show)


Note You need to log in before you can comment on or make changes to this bug.
Description Juriy 2010-11-20 11:00:06 UTC
When dispatch() method is called inside the onTimeout() function of the AsyncListener, the exception is thrown:

SEVERE: An exception or error occurred in the container during the request processing
java.lang.IllegalStateException: Calling [dispatchAsync()] is not valid for a request with Async state [TIMING_OUT]
	at org.apache.coyote.AsyncStateMachine.asyncDispatch(AsyncStateMachine.java:220)
	at org.apache.coyote.http11.Http11NioProcessor.actionInternal(Http11NioProcessor.java:672)
	at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:937)
	at org.apache.coyote.Request.action(Request.java:348)
	at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:173)
	at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:135)
	at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:130)
	at com.juriy.snowball.SnowServlet$1.onTimeout(SnowServlet.java:23)
	at org.apache.catalina.core.AsyncListenerWrapper.fireOnTimeout(AsyncListenerWrapper.java:45)
	at org.apache.catalina.core.AsyncContextImpl.timeout(AsyncContextImpl.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:270)
	at org.apache.coyote.http11.Http11NioProcessor.asyncDispatch(Http11NioProcessor.java:232)
	at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.event(Http11NioProtocol.java:305)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1526)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

The sample code is below:

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		AsyncContext context = request.startAsync();
		context.addListener(new AsyncListener() {

			public void onComplete(AsyncEvent asyncEvent) throws IOException {}

			public void onTimeout(AsyncEvent asyncEvent) throws IOException {
				System.out.println("HITTING TIMEOUT");

			public void onError(AsyncEvent asyncEvent) throws IOException {}

			public void onStartAsync(AsyncEvent asyncEvent) throws IOException {}

It looks like the Servlet 3.0 specification allows to do such call, here's the quotation that explicitly states the flow of the timeouted async contexts (page 18):

"In the event that an asynchronous operation times out, the container must run
through the following steps:
■ Invoke the AsyncListener.onTimeout method on all the AsyncListener
instances registered with the ServletRequest on which the asynchronous
operation was initiated.
■ If none of the listeners called AsyncContext.complete() or any of the
AsyncContext.dispatch methods, perform an error dispatch with a status
code equal to HttpServletResponse.SC_INTERNAL_SERVER_ERROR.
■ If no matching error page was found, or the error page did not call
AsyncContext.complete() or any of the AsyncContext.dispatch
methods, the container MUST call AsyncContext.complete()"

Second step assumes that the call to dispatch in onTimeout() is allowed.
Comment 1 Mark Thomas 2010-11-22 09:37:26 UTC
Thanks for the report. This has been fixed in 7.0.x and will be included in 7.0.5 onwards.