474634 - AsyncListener.onError() handling.

Added HttpConfiguration.maxErrorDispatches to detect error loops
Fixed ManyWays... unit test to handle error dispatch.
This commit is contained in:
Greg Wilkins 2015-08-14 10:05:50 +10:00
parent 173f6d8b3b
commit d780839bec
6 changed files with 57 additions and 2 deletions

View File

@ -87,6 +87,7 @@
<Set name="sendDateHeader"><Property name="jetty.httpConfig.sendDateHeader" deprecated="jetty.send.date.header" default="false" /></Set>
<Set name="headerCacheSize"><Property name="jetty.httpConfig.headerCacheSize" default="512" /></Set>
<Set name="delayDispatchUntilContent"><Property name="jetty.httpConfig.delayDispatchUntilContent" deprecated="jetty.delayDispatchUntilContent" default="true"/></Set>
<Set name="maxErrorDispatches"><Property name=jetty.httpConfig.maxErrorDispatches"/></Set>
<!-- Uncomment to enable handling of X-Forwarded- style headers
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>

View File

@ -61,6 +61,9 @@ etc/jetty.xml
## Whether, for requests with content, delay dispatch until some content has arrived
# jetty.httpConfig.delayDispatchUntilContent=true
## Maximum number of error dispatches to prevent looping
# jetty.httpConfig.maxErrorDispatches=10
### Server configuration
## Whether ctrl+c on the console gracefully stops the Jetty server
# jetty.server.stopAtShutdown=true

View File

@ -318,12 +318,34 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
case ERROR_DISPATCH:
{
Throwable ex = _state.getAsyncContextEvent().getThrowable();
// Check for error dispatch loops
Integer loop_detect = (Integer)_request.getAttribute("org.eclipse.jetty.server.ERROR_DISPATCH");
if (loop_detect==null)
loop_detect=new Integer(1);
else
loop_detect=loop_detect+1;
_request.setAttribute("org.eclipse.jetty.server.ERROR_DISPATCH",loop_detect);
if (loop_detect > getHttpConfiguration().getMaxErrorDispatches())
{
LOG.warn("ERROR_DISPATCH loop detected on {} {}",_request,ex);
try
{
_response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500);
}
finally
{
_state.errorComplete();
}
break loop;
}
_request.setHandled(false);
_response.resetBuffer();
_response.getHttpOutput().reopen();
_request.setDispatcherType(DispatcherType.ERROR);
Throwable ex = _state.getAsyncContextEvent().getThrowable();
String reason=null;
if (ex == null || ex instanceof TimeoutException)
{

View File

@ -63,6 +63,7 @@ public class HttpConfiguration
private boolean _sendDateHeader = true;
private boolean _delayDispatchUntilContent = true;
private boolean _persistentConnectionsEnabled = true;
private int _maxErrorDispatches = 10;
/* ------------------------------------------------------------ */
/**
@ -118,6 +119,7 @@ public class HttpConfiguration
_sendXPoweredBy=config._sendXPoweredBy;
_delayDispatchUntilContent=config._delayDispatchUntilContent;
_persistentConnectionsEnabled=config._persistentConnectionsEnabled;
_maxErrorDispatches=config._maxErrorDispatches;
}
/* ------------------------------------------------------------ */
@ -458,4 +460,23 @@ public class HttpConfiguration
{
return Boolean.TRUE.equals(_formEncodedMethods.get(method));
}
/* ------------------------------------------------------------ */
/**
* @return The maximum error dispatches for a request to prevent looping on an error
*/
@ManagedAttribute("The maximum ERROR dispatches for a request for loop prevention (default 10)")
public int getMaxErrorDispatches()
{
return _maxErrorDispatches;
}
/* ------------------------------------------------------------ */
/**
* @param max The maximum error dispatches for a request to prevent looping on an error
*/
public void setMaxErrorDispatches(int max)
{
_maxErrorDispatches=max;
}
}

View File

@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -86,6 +87,13 @@ public class HttpManyWaysToAsyncCommitBadBehaviourTest extends AbstractHttpTest
public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
final CyclicBarrier resumeBarrier = new CyclicBarrier(1);
if (baseRequest.getDispatcherType()==DispatcherType.ERROR)
{
response.sendError(500);
return;
}
if (request.getAttribute(CONTEXT_ATTRIBUTE) == null)
{
final AsyncContext asyncContext = baseRequest.startAsync();

View File

@ -659,7 +659,7 @@
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<version>3.0</version>
<version>3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>