420033 AsyncContext.onTimeout exceptions passed to onError

Conflicts:
	jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
	jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java
	jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
This commit is contained in:
Greg Wilkins 2013-10-24 15:30:35 +11:00
parent d38233c52d
commit ac3787b167
3 changed files with 88 additions and 8 deletions

View File

@ -274,10 +274,19 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
if (_request.getHttpChannelState().isExpired()) if (_request.getHttpChannelState().isExpired())
{ {
_request.setDispatcherType(DispatcherType.ERROR); _request.setDispatcherType(DispatcherType.ERROR);
Throwable ex=_state.getAsyncContextEvent().getThrowable();
String reason="Async Timeout";
if (ex!=null)
{
reason="Async Exception";
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,ex);
}
_request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500)); _request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
_request.setAttribute(RequestDispatcher.ERROR_MESSAGE,"Async Timeout"); _request.setAttribute(RequestDispatcher.ERROR_MESSAGE,reason);
_request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI()); _request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
_response.setStatusWithReason(500,"Async Timeout");
_response.setStatusWithReason(500,reason);
ErrorHandler eh = _state.getContextHandler().getErrorHandler(); ErrorHandler eh = _state.getContextHandler().getErrorHandler();
if (eh instanceof ErrorHandler.ErrorPageMapper) if (eh instanceof ErrorHandler.ErrorPageMapper)

View File

@ -348,7 +348,7 @@ public class HttpChannelState
protected void expired() protected void expired()
{ {
final List<AsyncListener> aListeners; final List<AsyncListener> aListeners;
AsyncEvent event; AsyncContextEvent event;
synchronized (this) synchronized (this)
{ {
switch(_state) switch(_state)
@ -374,7 +374,10 @@ public class HttpChannelState
} }
catch(Exception e) catch(Exception e)
{ {
LOG.warn(e); LOG.debug(e);
event.setThrowable(e);
_channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
break;
} }
} }
} }

View File

@ -28,7 +28,10 @@ import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -76,6 +79,7 @@ public class AsyncContextTest
_contextHandler.addServlet(new ServletHolder(new ForwardingServlet()),"/forward"); _contextHandler.addServlet(new ServletHolder(new ForwardingServlet()),"/forward");
_contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()),"/dispatchingServlet"); _contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()),"/dispatchingServlet");
_contextHandler.addServlet(new ServletHolder(new ExpireServlet()),"/expire/*"); _contextHandler.addServlet(new ServletHolder(new ExpireServlet()),"/expire/*");
_contextHandler.addServlet(new ServletHolder(new BadExpireServlet()),"/badexpire/*");
_contextHandler.addServlet(new ServletHolder(new ErrorServlet()),"/error/*"); _contextHandler.addServlet(new ServletHolder(new ErrorServlet()),"/error/*");
ErrorPageErrorHandler error_handler = new ErrorPageErrorHandler(); ErrorPageErrorHandler error_handler = new ErrorPageErrorHandler();
@ -287,8 +291,11 @@ public class AsyncContextTest
@Test @Test
public void testExpire() throws Exception public void testExpire() throws Exception
{ {
String request = "GET /ctx/expire HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" String request = "GET /ctx/expire HTTP/1.1\r\n" +
+ "Connection: close\r\n" + "\r\n"; "Host: localhost\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Connection: close\r\n" +
"\r\n";
String responseString = _connector.getResponses(request); String responseString = _connector.getResponses(request);
BufferedReader br = new BufferedReader(new StringReader(responseString)); BufferedReader br = new BufferedReader(new StringReader(responseString));
@ -299,7 +306,28 @@ public class AsyncContextTest
br.readLine();// server br.readLine();// server
br.readLine();// empty br.readLine();// empty
Assert.assertEquals("error servlet","ERROR:/error",br.readLine()); Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
}
@Test
public void testBadExpire() throws Exception
{
String request = "GET /ctx/badexpire HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Connection: close\r\n" +
"\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = new BufferedReader(new StringReader(responseString));
assertEquals("HTTP/1.1 500 Async Exception",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
Assert.assertEquals("error servlet","ERROR: /error",br.readLine());
Assert.assertEquals("error servlet","EXCEPTION: java.io.IOException: TEST",br.readLine());
} }
private class DispatchingRunnable implements Runnable private class DispatchingRunnable implements Runnable
@ -336,7 +364,9 @@ public class AsyncContextTest
@Override @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{ {
response.getOutputStream().print("ERROR:" + request.getServletPath() + "\n"); response.getOutputStream().print("ERROR: " + request.getServletPath() + "\n");
if (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)!=null)
response.getOutputStream().print("EXCEPTION: " + request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) + "\n");
} }
} }
@ -355,6 +385,44 @@ public class AsyncContextTest
} }
} }
private class BadExpireServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
if (request.getDispatcherType()==DispatcherType.REQUEST)
{
AsyncContext asyncContext = request.startAsync();
asyncContext.addListener(new AsyncListener()
{
@Override
public void onTimeout(AsyncEvent event) throws IOException
{
throw new IOException("TEST");
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
@Override
public void onError(AsyncEvent event) throws IOException
{
}
@Override
public void onComplete(AsyncEvent event) throws IOException
{
}
});
asyncContext.setTimeout(100);
}
}
}
private class TestServlet extends HttpServlet private class TestServlet extends HttpServlet
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;