Skip to content

Commit

Permalink
Merge branch 'DRY/ThrottleRequestsWithRedis' of https://github.com/th…
Browse files Browse the repository at this point in the history
…emsaid/framework into themsaid-DRY/ThrottleRequestsWithRedis
  • Loading branch information
taylorotwell committed Aug 26, 2017
2 parents 774719e + 0d93864 commit dfa0209
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 103 deletions.
13 changes: 12 additions & 1 deletion src/Illuminate/Routing/Middleware/ThrottleRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ protected function resolveRequestSignature($request)
*/
protected function buildException($key, $maxAttempts)
{
$retryAfter = $this->limiter->availableIn($key);
$retryAfter = $this->getTimeUntilNextRetry($key);

$headers = $this->getHeaders(
$maxAttempts,
Expand All @@ -122,6 +122,17 @@ protected function buildException($key, $maxAttempts)
);
}

/**
* Get the number of seconds until the next retry.
*
* @param string $key
* @return int
*/
protected function getTimeUntilNextRetry($key)
{
return $this->limiter->availableIn($key);
}

/**
* Add the limit header information to the given response.
*
Expand Down
107 changes: 5 additions & 102 deletions src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,11 @@
namespace Illuminate\Routing\Middleware;

use Closure;
use RuntimeException;
use Illuminate\Support\Str;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Redis\Limiters\DurationLimiter;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Contracts\Redis\Factory as Redis;
use Symfony\Component\HttpKernel\Exception\HttpException;

class ThrottleRequestsWithRedis
class ThrottleRequestsWithRedis extends ThrottleRequests
{
use InteractsWithTime;

/**
* The Redis factory implementation.
*
Expand Down Expand Up @@ -76,104 +69,14 @@ public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes
}

/**
* Resolve the number of attempts if the user is authenticated or not.
*
* @param \Illuminate\Http\Request $request
* @param int|string $maxAttempts
* @return int
*/
protected function resolveMaxAttempts($request, $maxAttempts)
{
if (Str::contains($maxAttempts, '|')) {
$maxAttempts = explode('|', $maxAttempts, 2)[$request->user() ? 1 : 0];
}

return (int) $maxAttempts;
}

/**
* Resolve request signature.
*
* @param \Illuminate\Http\Request $request
* @return string
* @throws \RuntimeException
*/
protected function resolveRequestSignature($request)
{
if ($user = $request->user()) {
return sha1($user->getAuthIdentifier());
}

if ($route = $request->route()) {
return sha1($route->getDomain().'|'.$request->ip());
}

throw new RuntimeException(
'Unable to generate the request signature. Route unavailable.'
);
}

/**
* Create a 'too many attempts' exception.
* Get the number of seconds until the next retry.
*
* @param string $key
* @param int $maxAttempts
* @return \Symfony\Component\HttpKernel\Exception\HttpException
*/
protected function buildException($key, $maxAttempts)
{
$retryAfter = $this->decaysAt - $this->currentTime();

$headers = $this->getHeaders(
$maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter),
$retryAfter
);

return new HttpException(
429, 'Too Many Attempts.', null, $headers
);
}

/**
* Add the limit header information to the given response.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* @param int $maxAttempts
* @param int $remainingAttempts
* @param int|null $retryAfter
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function addHeaders(Response $response, $maxAttempts, $remainingAttempts, $retryAfter = null)
{
$response->headers->add(
$this->getHeaders($maxAttempts, $remainingAttempts, $retryAfter)
);

return $response;
}

/**
* Get the limit headers information.
*
* @param int $maxAttempts
* @param int $remainingAttempts
* @param int|null $retryAfter
* @return array
* @return int
*/
protected function getHeaders($maxAttempts, $remainingAttempts, $retryAfter = null)
protected function getTimeUntilNextRetry($key)
{
$headers = [
'X-RateLimit-Limit' => $maxAttempts,
'X-RateLimit-Remaining' => $remainingAttempts,
];

if (! is_null($retryAfter)) {
$headers['Retry-After'] = $retryAfter;
$headers['X-RateLimit-Reset'] = $this->availableAt($retryAfter);
}

return $headers;
return $this->decaysAt - $this->currentTime();
}

/**
Expand Down

0 comments on commit dfa0209

Please sign in to comment.