diff --git a/src/Drivers/LaravelHttpServer.php b/src/Drivers/LaravelHttpServer.php index ffa12a6c..0d336751 100644 --- a/src/Drivers/LaravelHttpServer.php +++ b/src/Drivers/LaravelHttpServer.php @@ -15,6 +15,7 @@ use Amp\Http\Server\SocketHttpServer; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Http\Kernel as HttpKernel; +use Illuminate\Cookie\CookieJar; use Illuminate\Foundation\Testing\Concerns\WithoutExceptionHandlingHandler; use Illuminate\Http\Request; use Illuminate\Routing\UrlGenerator; @@ -273,6 +274,9 @@ private function handleRequest(AmpRequest $request): Response $debug = config('app.debug'); + // The container is reused, so flush stale queued cookies (FPM/Octane start fresh). + app()->make(CookieJar::class)->flushQueuedCookies(); + try { config(['app.debug' => false]); diff --git a/tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php b/tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php index 7ca9688e..77ab4dbe 100644 --- a/tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php +++ b/tests/Unit/Drivers/Laravel/LaravelHttpServerTest.php @@ -2,7 +2,12 @@ declare(strict_types=1); +use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; +use Illuminate\Foundation\Http\Events\RequestHandled; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cookie; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Route; use function Pest\Laravel\withServerVariables; use function Pest\Laravel\withUnencryptedCookie; @@ -57,3 +62,27 @@ visit('/server-variables') ->assertSee('"test-server-key":"test value"'); }); + +it('does not re-send a cookie queued in an earlier request', function (): void { + // Without flush the second response would re-send the queued cookie. + Route::get('/queue-cookie', function (): string { + Cookie::queue('queued-probe', 'first-request', 5); + + return 'queued'; + })->middleware(AddQueuedCookiesToResponse::class); + Route::get('/no-cookie', fn (): string => 'plain')->middleware(AddQueuedCookiesToResponse::class); + + $queued = []; + Event::listen(RequestHandled::class, function (RequestHandled $event) use (&$queued): void { + foreach ($event->response->headers->getCookies() as $cookie) { + if ($cookie->getName() === 'queued-probe') { + $queued[] = $event->request->path(); + } + } + }); + + visit('/queue-cookie')->assertSee('queued'); + visit('/no-cookie')->assertSee('plain'); + + expect($queued)->toBe(['queue-cookie']); +});