protected long _delayMs;超过最大处理请求数当前请求的等待时间,-1立即拒绝,0,无限等待,正数表达等待的毫秒数
protected long _throttleMs;异步等待获取信号量的时间
protected long _maxWaitMs;阻塞等待获取信号量的时间
protected long _maxRequestMs;请求处理最大时间限制
protected long _maxIdleTrackerMs;跟踪连接是否断开的最大等待时间
protected int _throttledRequests;允许在等待队列中等待获取信号量的请求数
protected int _maxRequestsPerSec; 每秒允许处理最多的请求数,超过将延迟,异步等待。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain) throws IOException, ServletException
{
final HttpServletRequest srequest = (HttpServletRequest)request;
final HttpServletResponse sresponse = (HttpServletResponse)response;
final long now=_requestTimeoutQ.getNow();
// Look for the rate tracker for this request
RateTracker tracker = (RateTracker)request.getAttribute(__TRACKER);
if (tracker==null) //如果request没有进行过dosfilter的处理
{
// This is the first time we have seen this request.
// get a rate tracker associated with this request, and record one hit
tracker = getRateTracker(request); //根据request生成dos跟踪的对象,看下面方法
// Calculate the rate and check it is over the allowed limit
final boolean overRateLimit = tracker.isRateExceeded(now);//判断是否已经超过每秒最大处理请求数
// pass it through if we are not currently over the rate limit
if (!overRateLimit)//如果没有超过,则正常处理
{
doFilterChain(filterchain,srequest,sresponse);
return;
}
// We are over the limit.
Log.warn("DOS ALERT: ip="+srequest.getRemoteAddr()+",session="+srequest.getRequestedSessionId()+",user="+srequest.getUserPrincipal());
// So either reject it, delay it or throttle it
switch((int)_delayMs) //根据当前配置的延时时间
{
case -1: //如果为-1,则直接拒绝
{
// Reject this request
if (_insertHeaders) //是否把dosfilter处理插入response的header
((HttpServletResponse)response).addHeader("DoSFilter","unavailable");
((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
return;
}
case 0: //如果为0,则当前线程继续等待处理,
{
// fall through to throttle code
request.setAttribute(__TRACKER,tracker);
break;
}
default://其他字段,则设置request的timeout时间为_delayMs,并且挂起当前线程,返回
{
// insert a delay before throttling the request
if (_insertHeaders)
((HttpServletResponse)response).addHeader("DoSFilter","delayed");
Continuation continuation = ContinuationSupport.getContinuation(request);
request.setAttribute(__TRACKER,tracker);
if (_delayMs > 0)
continuation.setTimeout(_delayMs);
continuation.suspend();
return;
}
}
}
//_delayMs为0是,当前请求继续等待
// Throttle the request
boolean accepted = false;
try
{
// check if we can afford to accept another request at this time
accepted = _passes.tryAcquire(_maxWaitMs,TimeUnit.MILLISECONDS);//判断当前处理请求队列是否已经有处理完的请求,处理完的会释放信号量,则当前请求线程可以获取信号量
if (!accepted) //如果不能获取,则把当前请求设置为异步等待,异步等待的时间为_throttleMs,
{
// we were not accepted, so either we suspend to wait,or if we were woken up we insist or we fail
final Continuation continuation = ContinuationSupport.getContinuation(request);
Boolean throttled = (Boolean)request.getAttribute(__THROTTLED);
if (throttled!=Boolean.TRUE && _throttleMs>0)
{
int priority = getPriority(request,tracker);
request.setAttribute(__THROTTLED,Boolean.TRUE);
if (_insertHeaders)
((HttpServletResponse)response).addHeader("DoSFilter","throttled");
if (_throttleMs > 0)
continuation.setTimeout(_throttleMs);
continuation.suspend();
continuation.addContinuationListener(_listener[priority]);
_queue[priority].add(continuation);
return;
}
// else were we resumed?
else if (request.getAttribute("javax.servlet.resumed")==Boolean.TRUE)
{//如果线程中心被唤醒,则可以获取到信号量,
// we were resumed and somebody stole our pass, so we wait for the next one.
_passes.acquire();
accepted = true;
}
}
// if we were accepted (either immediately or after throttle)
if (accepted) //获取到了,继续执行,
// call the chain
doFilterChain(filterchain,srequest,sresponse);
else
{
// fail the request
if (_insertHeaders)
((HttpServletResponse)response).addHeader("DoSFilter","unavailable");
((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
}
}
catch (InterruptedException e)
{
_context.log("DoS",e);
((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
}
finally
{
if (accepted) //执行完了之后释放当前的信号量,唤醒等待队列中的第一个请求进行处理
{
// wake up the next highest priority request.
for (int p = _queue.length; p-- > 0;)
{
Continuation continuation = _queue[p].poll();
if (continuation != null && continuation.isSuspended())
{
continuation.resume();
break;
}
}
_passes.release();
}
}
}
public RateTracker getRateTracker(ServletRequest request)
{
HttpServletRequest srequest = (HttpServletRequest)request;
HttpSession session=srequest.getSession(false);
String loadId = extractUserId(request);
final int type;
if (loadId != null)
{
type = USER_AUTH;
}
else
{
if (_trackSessions && session!=null && !session.isNew())
{
loadId=session.getId();
type = USER_SESSION;
}
else
{
loadId = _remotePort?(request.getRemoteAddr()+request.getRemotePort()):request.getRemoteAddr();
type = USER_IP;
}
}
RateTracker tracker=_rateTrackers.get(loadId);
if (tracker==null)
{
RateTracker t;
if (_whitelist.contains(request.getRemoteAddr())) //如果在白名单中,则isRateExceeded一直返回false
{
t = new FixedRateTracker(loadId,type,_maxRequestsPerSec);
}
else
{
t = new RateTracker(loadId,type,_maxRequestsPerSec);
}
tracker=_rateTrackers.putIfAbsent(loadId,t);
if (tracker==null)
tracker=t;
if (type == USER_IP)
{
// USER_IP expiration from _rateTrackers is handled by the _trackerTimeoutQ
synchronized (_trackerTimeoutQ)
{
_trackerTimeoutQ.schedule(tracker);
}
}
else if (session!=null)
// USER_SESSION expiration from _rateTrackers are handled by the HttpSessionBindingListener
session.setAttribute(__TRACKER,tracker);
}
return tracker;
}