Added RFC6585 status codes and use 429 for DoSFilter

This commit is contained in:
Greg Wilkins 2014-11-12 14:16:41 +11:00
parent 39360d91e6
commit 1834e360ea
3 changed files with 49 additions and 19 deletions

View File

@ -668,6 +668,7 @@ public class HttpStatus
public final static int UNPROCESSABLE_ENTITY_422 = 422;
public final static int LOCKED_423 = 423;
public final static int FAILED_DEPENDENCY_424 = 424;
public final static int UPGRADE_REQUIRED_426 = 426;
public final static int INTERNAL_SERVER_ERROR_500 = 500;
public final static int NOT_IMPLEMENTED_501 = 501;
@ -677,8 +678,13 @@ public class HttpStatus
public final static int HTTP_VERSION_NOT_SUPPORTED_505 = 505;
public final static int INSUFFICIENT_STORAGE_507 = 507;
public static final int MAX_CODE = 507;
// RFC 6585
public final static int PRECONDITION_REQUIRED_428 = 428;
public final static int TOO_MANY_REQUESTS_429 = 429;
public final static int REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431;
public final static int NETWORK_AUTHENTICATION_REQUIRED_511 = 511;
public static final int MAX_CODE = 511;
private static final Code[] codeMap = new Code[MAX_CODE+1];
@ -802,7 +808,17 @@ public class HttpStatus
LOCKED(LOCKED_423, "Locked"),
/** <code>424 Failed Dependency</code> */
FAILED_DEPENDENCY(FAILED_DEPENDENCY_424, "Failed Dependency"),
/** <code>426 Upgrade Required (RFC7231)</code> */
UPGRADE_REQUIRED(UPGRADE_REQUIRED_426, "Upgrade Required"),
/** <code>428 Precondition Required (RFC6585)</code> */
PRECONDITION_REQUIRED(PRECONDITION_REQUIRED_428, "Precondition Required"),
/** <code>429 Too Many Requests (RFC6585)</code> */
TOO_MANY_REQUESTS(TOO_MANY_REQUESTS_429, "Too Many Requests"),
/** <code>431 Request Header Fields Too Large (RFC6585)</code> */
REQUEST_HEADER_FIELDS_TOO_LARGE(REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Request Header Fields Too Large"),
/*
* --------------------------------------------------------------------
* Server Error messages in 5xx series. As defined by ... RFC 1945 -
@ -822,8 +838,13 @@ public class HttpStatus
/** <code>505 HTTP Version Not Supported</code> */
HTTP_VERSION_NOT_SUPPORTED(HTTP_VERSION_NOT_SUPPORTED_505, "HTTP Version Not Supported"),
/** <code>507 Insufficient Storage</code> */
INSUFFICIENT_STORAGE(INSUFFICIENT_STORAGE_507, "Insufficient Storage");
INSUFFICIENT_STORAGE(INSUFFICIENT_STORAGE_507, "Insufficient Storage"),
/** <code>511 Network Authentication Required (RFC6585)</code> */
NETWORK_AUTHENTICATION_REQUIRED(NETWORK_AUTHENTICATION_REQUIRED_511, "Network Authentication Required"),
;
private final int _code;
private final String _message;

View File

@ -91,40 +91,33 @@ import org.eclipse.jetty.util.thread.Scheduler;
* <dd>is the delay given to all requests over the rate limit,
* before they are considered at all. -1 means just reject request,
* 0 means no delay, otherwise it is the delay.</dd>
* <p/>
* <dt>maxWaitMs</dt>
* <dd>how long to blocking wait for the throttle semaphore.</dd>
* <p/>
* <dt>throttledRequests</dt>
* <dd>is the number of requests over the rate limit able to be
* considered at once.</dd>
* <p/>
* <dt>throttleMs</dt>
* <dd>how long to async wait for semaphore.</dd>
* <p/>
* <dt>maxRequestMs</dt>
* <dd>how long to allow this request to run.</dd>
* <p/>
* <dt>maxIdleTrackerMs</dt>
* <dd>how long to keep track of request rates for a connection,
* before deciding that the user has gone away, and discarding it</dd>
* <p/>
* <dt>insertHeaders</dt>
* <dd>if true , insert the DoSFilter headers into the response. Defaults to true.</dd>
* <p/>
* <dt>trackSessions</dt>
* <dd>if true, usage rate is tracked by session if a session exists. Defaults to true.</dd>
* <p/>
* <dt>remotePort</dt>
* <dd>if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false.</dd>
* <p/>
* <dt>ipWhitelist</dt>
* <dd>a comma-separated list of IP addresses that will not be rate limited</dd>
* <p/>
* <dt>managedAttr</dt>
* <dd>if set to true, then this servlet is set as a {@link ServletContext} attribute with the
* filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to
* manage the configuration of the filter.</dd>
* <dt>tooManyCode</dt>
* <dd>The status code to send if there are too many requests. By default is 429 (too many requests), but 503 (Unavailable) is
* another option</dd>
* </dl>
* </p>
*/
@ -163,6 +156,7 @@ public class DoSFilter implements Filter
static final String REMOTE_PORT_INIT_PARAM = "remotePort";
static final String IP_WHITELIST_INIT_PARAM = "ipWhitelist";
static final String ENABLED_INIT_PARAM = "enabled";
static final String TOO_MANY_CODE = "tooManyCode";
private static final int USER_AUTH = 2;
private static final int USER_SESSION = 2;
@ -173,6 +167,7 @@ public class DoSFilter implements Filter
private final String _resumed = "DoSFilter@" + Integer.toHexString(hashCode()) + ".RESUMED";
private final ConcurrentHashMap<String, RateTracker> _rateTrackers = new ConcurrentHashMap<>();
private final List<String> _whitelist = new CopyOnWriteArrayList<>();
private int _tooManyCode;
private volatile long _delayMs;
private volatile long _throttleMs;
private volatile long _maxWaitMs;
@ -260,7 +255,10 @@ public class DoSFilter implements Filter
parameter = filterConfig.getInitParameter(ENABLED_INIT_PARAM);
setEnabled(parameter == null || Boolean.parseBoolean(parameter));
parameter = filterConfig.getInitParameter(TOO_MANY_CODE);
setTooManyCode(parameter==null?429:Integer.parseInt(parameter));
_scheduler = startScheduler();
ServletContext context = filterConfig.getServletContext();
@ -331,7 +329,7 @@ public class DoSFilter implements Filter
LOG.warn("DOS ALERT: Request rejected ip={}, session={}, user={}", request.getRemoteAddr(), request.getRequestedSessionId(), request.getUserPrincipal());
if (insertHeaders)
response.addHeader("DoSFilter", "unavailable");
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
response.sendError(getTooManyCode());
return;
}
case 0:
@ -414,12 +412,13 @@ public class DoSFilter implements Filter
LOG.debug("Rejecting {}", request);
if (isInsertHeaders())
response.addHeader("DoSFilter", "unavailable");
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
response.sendError(getTooManyCode());
}
}
catch (InterruptedException e)
{
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
LOG.ignore(e);
response.sendError(getTooManyCode());
}
finally
{
@ -980,6 +979,16 @@ public class DoSFilter implements Filter
{
_enabled = enabled;
}
public int getTooManyCode()
{
return _tooManyCode;
}
public void setTooManyCode(int tooManyCode)
{
_tooManyCode = tooManyCode;
}
/**
* Get a list of IP addresses that will not be rate limited.

View File

@ -260,7 +260,7 @@ public abstract class AbstractDoSFilterTest
// System.err.println("RESPONSES: \n"+responses);
assertEquals(4,count(responses,"HTTP/1.1 200 OK"));
assertEquals(1,count(responses,"HTTP/1.1 503"));
assertEquals(1,count(responses,"HTTP/1.1 429"));
assertEquals(1,count(responses,"DoSFilter: delayed"));
assertEquals(1,count(responses,"DoSFilter: throttled"));
assertEquals(1,count(responses,"DoSFilter: unavailable"));