Skip to content

Commit

Permalink
Fix array cache driver expiry
Browse files Browse the repository at this point in the history
  • Loading branch information
timacdonald committed Sep 22, 2023
1 parent 22d4530 commit 4c1dc79
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Illuminate/Cache/ArrayStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function get($key)

$expiresAt = $item['expiresAt'] ?? 0;

if ($expiresAt !== 0 && $this->currentTime() > $expiresAt) {
if ($expiresAt !== 0 && $this->currentTime() >= $expiresAt) {
$this->forget($key);

return;
Expand Down
61 changes: 61 additions & 0 deletions tests/Integration/Http/ThrottleRequestsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Cache\RateLimiter;
use Illuminate\Cache\RateLimiting\GlobalLimit;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Container\Container;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Routing\Middleware\ThrottleRequests;
Expand Down Expand Up @@ -116,4 +117,64 @@ public function testItCanGenerateDefinitionViaStaticMethod()
$signature = (string) ThrottleRequests::with(prefix: 'foo');
$this->assertSame('Illuminate\Routing\Middleware\ThrottleRequests:60,1,foo', $signature);
}

public function testItCanThrottlePerMinute()
{
$rateLimiter = Container::getInstance()->make(RateLimiter::class);
$rateLimiter->for('test', fn () => Limit::perMinute(3));
Route::get('/', fn () => 'ok')->middleware(ThrottleRequests::using('test'));

Carbon::setTestNow('2000-01-01 00:00:00.000');

// Make 3 requests that should all be successful. The first request is
// at the VERY start of the second. That is important to remember.
// Assertions before each request to make sure we know the time.

for ($i = 0; $i < 3; $i++) {
match ($i) {
0 => $this->assertSame('2000-01-01 00:00:00.000', now()->toDateTimeString('m')),
1 => $this->assertSame('2000-01-01 00:00:01.000', now()->toDateTimeString('m')),
2 => $this->assertSame('2000-01-01 00:00:02.000', now()->toDateTimeString('m')),
};

$response = $this->get('/');
$response->assertOk();
$response->assertContent('ok');
$response->assertHeader('X-RateLimit-Limit', 3);
$response->assertHeader('X-RateLimit-Remaining', 3 - ($i + 1));

Carbon::setTestNow(now()->addSecond());
}

// It is now 3 seconds past and we will make another request that
// should be rate limited.

$this->assertSame('2000-01-01 00:00:03.000', now()->toDateTimeString('m'));

$response = $this->get('/');
$response->assertStatus(429);
$response->assertHeader('Retry-After', 57);
$response->assertHeader('X-RateLimit-Reset', now()->addSeconds(57)->timestamp);
$response->assertHeader('X-RateLimit-Limit', 3);
$response->assertHeader('X-RateLimit-Remaining', 0);

// We will now make it the very end of the minute, to check boundaries, and
// make another request that should be rate limited and tell us to try
// again in 1 second.
Carbon::setTestNow(now()->endOfMinute());
$this->assertSame('2000-01-01 00:00:59.999', now()->toDateTimeString('m'));

$response = $this->get('/');
$response->assertHeader('Retry-After', 1);
$response->assertHeader('X-RateLimit-Reset', now()->addSeconds(1)->timestamp);
$response->assertHeader('X-RateLimit-Limit', 3);
$response->assertHeader('X-RateLimit-Remaining', 0);

// We now tick over into the next second. We should now be able to make
// requests again.
Carbon::setTestNow('2000-01-01 00:01:00.000');

$response = $this->get('/');
$response->assertOk();
}
}

0 comments on commit 4c1dc79

Please sign in to comment.