Skip to content

Commit

Permalink
Merge pull request #1 from headsnet/respond-with-http-429
Browse files Browse the repository at this point in the history
Respond with HTTP 429 when receiving too many requests
  • Loading branch information
benr77 authored Jun 25, 2024
2 parents 37f5d48 + e9ac4f6 commit eb41cfb
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/RateLimiting/ApplyRateLimitingSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\RateLimiter\RateLimiterFactory;

Expand Down Expand Up @@ -48,6 +49,11 @@ private function ensureRateLimiting(Request $request, RateLimiterFactory $rateLi
$limiterKey = sprintf('rate_limit_ip_%s', $request->getClientIp());
$limit = $rateLimiter->create($limiterKey)->consume();
$request->attributes->set('rate_limit', $limit);
$limit->ensureAccepted();

if (false === $limit->isAccepted()) {
throw new TooManyRequestsHttpException(
$limit->getRetryAfter()->format(\DateTimeInterface::RFC7231)
);
}
}
}
20 changes: 18 additions & 2 deletions tests/RateLimiting/ApplyRateLimitingSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\RateLimiter\RateLimit;
Expand All @@ -19,6 +20,8 @@
#[CoversClass(ApplyRateLimitingSubscriber::class)]
class ApplyRateLimitingSubscriberTest extends TestCase
{
private const MAX_PER_PERIOD = 2;

#[Test]
public function get_subscribed_events_returns_correct_event_and_priority(): void
{
Expand Down Expand Up @@ -88,6 +91,19 @@ public function ensure_rate_limiting_sets_rate_limit_attribute(): void
$this->assertTrue($rateLimit->isAccepted());
}

#[Test]
public function ensure_http_429_is_returned_after_too_many_requests(): void
{
[, $event] = $this->createControllerEvent();
$sut = new ApplyRateLimitingSubscriber($this->getRateLimiterClassMap());

$this->expectException(TooManyRequestsHttpException::class);

for ($i = 0; $i <= self::MAX_PER_PERIOD; $i++) {
$sut->onKernelController($event);
}
}

/**
* @return array{Request, ControllerEvent}
*/
Expand All @@ -114,9 +130,9 @@ private function getRateLimiterClassMap(): array
[
'id' => 'test',
'policy' => 'token_bucket',
'limit' => 10,
'limit' => self::MAX_PER_PERIOD,
'rate' => [
'interval' => '1 minute',
'interval' => '10 seconds',
],
],
new InMemoryStorage()
Expand Down

0 comments on commit eb41cfb

Please sign in to comment.