getRateLimiter()) {
$limiter = RateLimiter::create(
$this->getKeyFromRequest($request),
$this->getMaxAttempts(),
$this->getDecay()
);
}
if ($limiter->canAccess()) {
$limiter->hit();
$response = $delegate($request);
} else {
$response = $this->getErrorHTTPResponse();
}
$this->addHeadersToResponse($response, $limiter);
return $response;
}
/**
* @param HTTPRequest $request
* @return string
*/
protected function getKeyFromRequest($request)
{
$key = $this->getExtraKey() ? $this->getExtraKey() . '-' : '';
$key .= $request->getHost() . '-';
if ($currentUser = Security::getCurrentUser()) {
$key .= $currentUser->ID;
} else {
$key .= $request->getIP();
}
return md5($key);
}
/**
* @return HTTPResponse
*/
protected function getErrorHTTPResponse()
{
return HTTPResponse::create('
429 - Too many requests
', 429);
}
/**
* @param HTTPResponse $response
* @param RateLimiter $limiter
*/
protected function addHeadersToResponse($response, $limiter)
{
$response->addHeader('X-RateLimit-Limit', $limiter->getMaxAttempts());
$response->addHeader('X-RateLimit-Remaining', $remaining = $limiter->getNumAttemptsRemaining());
$ttl = $limiter->getTimeToReset();
$response->addHeader('X-RateLimit-Reset', DBDatetime::now()->getTimestamp() + $ttl);
if ($remaining <= 0) {
$response->addHeader('Retry-After', $ttl);
}
}
/**
* @param string $key
* @return $this
*/
public function setExtraKey($key)
{
$this->extraKey = $key;
return $this;
}
/**
* @return string
*/
public function getExtraKey()
{
return $this->extraKey;
}
/**
* @param int $maxAttempts
* @return $this
*/
public function setMaxAttempts($maxAttempts)
{
$this->maxAttempts = $maxAttempts;
return $this;
}
/**
* @return int
*/
public function getMaxAttempts()
{
return $this->maxAttempts;
}
/**
* @param int $decay Time in minutes
* @return $this
*/
public function setDecay($decay)
{
$this->decay = $decay;
return $this;
}
/**
* @return int
*/
public function getDecay()
{
return $this->decay;
}
/**
* @param RateLimiter $rateLimiter
* @return $this
*/
public function setRateLimiter($rateLimiter)
{
$this->rateLimiter = $rateLimiter;
return $this;
}
/**
* @return RateLimiter|null
*/
public function getRateLimiter()
{
return $this->rateLimiter;
}
}