diff --git a/src/HttpCache/EventListener/AddHeadersListener.php b/src/HttpCache/EventListener/AddHeadersListener.php index 9ea49d7f951..fec4997f8ee 100644 --- a/src/HttpCache/EventListener/AddHeadersListener.php +++ b/src/HttpCache/EventListener/AddHeadersListener.php @@ -32,8 +32,10 @@ final class AddHeadersListener private $vary; private $public; private $resourceMetadataFactory; + private $staleWhileRevalidate; + private $staleIfError; - public function __construct(bool $etag = false, int $maxAge = null, int $sharedMaxAge = null, array $vary = null, bool $public = null, ResourceMetadataFactoryInterface $resourceMetadataFactory = null) + public function __construct(bool $etag = false, int $maxAge = null, int $sharedMaxAge = null, array $vary = null, bool $public = null, ResourceMetadataFactoryInterface $resourceMetadataFactory = null, int $staleWhileRevalidate = null, int $staleIfError = null) { $this->etag = $etag; $this->maxAge = $maxAge; @@ -41,6 +43,8 @@ public function __construct(bool $etag = false, int $maxAge = null, int $sharedM $this->vary = $vary; $this->public = $public; $this->resourceMetadataFactory = $resourceMetadataFactory; + $this->staleWhileRevalidate = $staleWhileRevalidate; + $this->staleIfError = $staleIfError; } public function onKernelResponse(ResponseEvent $event): void @@ -83,5 +87,13 @@ public function onKernelResponse(ResponseEvent $event): void if (null !== $this->public && !$response->headers->hasCacheControlDirective('public')) { $this->public ? $response->setPublic() : $response->setPrivate(); } + + if (null !== ($staleWhileRevalidate = $resourceCacheHeaders['stale_while_revalidate'] ?? $this->staleWhileRevalidate) && !$response->headers->hasCacheControlDirective('stale-while-revalidate')) { + $response->headers->addCacheControlDirective('stale-while-revalidate', $staleWhileRevalidate); + } + + if (null !== ($staleIfError = $resourceCacheHeaders['stale_if_error'] ?? $this->staleIfError) && !$response->headers->hasCacheControlDirective('stale-if-error')) { + $response->headers->addCacheControlDirective('stale-if-error', $staleIfError); + } } } diff --git a/tests/HttpCache/EventListener/AddHeadersListenerTest.php b/tests/HttpCache/EventListener/AddHeadersListenerTest.php index 2e5e2af634a..9206b96dc31 100644 --- a/tests/HttpCache/EventListener/AddHeadersListenerTest.php +++ b/tests/HttpCache/EventListener/AddHeadersListenerTest.php @@ -102,11 +102,11 @@ public function testAddHeaders() $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn(new ResourceMetadata())->shouldBeCalled(); - $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); + $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal(), 15, 30); $listener->onKernelResponse($event->reveal()); $this->assertSame('"9893532233caff98cd083a116b013c0b"', $response->getEtag()); - $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); + $this->assertSame('max-age=100, public, s-maxage=200, stale-if-error=30, stale-while-revalidate=15', $response->headers->get('Cache-Control')); $this->assertSame(['Accept', 'Cookie', 'Accept-Encoding'], $response->getVary()); } @@ -126,11 +126,11 @@ public function testDoNotSetHeaderWhenAlreadySet() $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn(new ResourceMetadata())->shouldBeCalled(); - $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); + $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal(), 15, 30); $listener->onKernelResponse($event->reveal()); $this->assertSame('"etag"', $response->getEtag()); - $this->assertSame('max-age=300, public, s-maxage=400', $response->headers->get('Cache-Control')); + $this->assertSame('max-age=300, public, s-maxage=400, stale-if-error=30, stale-while-revalidate=15', $response->headers->get('Cache-Control')); $this->assertSame(['Accept', 'Cookie', 'Accept-Encoding'], $response->getVary()); } @@ -143,14 +143,14 @@ public function testSetHeadersFromResourceMetadata() $event->getRequest()->willReturn($request)->shouldBeCalled(); $event->getResponse()->willReturn($response)->shouldBeCalled(); - $metadata = new ResourceMetadata(null, null, null, null, null, ['cache_headers' => ['max_age' => 123, 'shared_max_age' => 456, 'vary' => ['Vary-1', 'Vary-2']]]); + $metadata = new ResourceMetadata(null, null, null, null, null, ['cache_headers' => ['max_age' => 123, 'shared_max_age' => 456, 'stale_while_revalidate' => 928, 'stale_if_error' => 70, 'vary' => ['Vary-1', 'Vary-2']]]); $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); - $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); + $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal(), 15, 30); $listener->onKernelResponse($event->reveal()); - $this->assertSame('max-age=123, public, s-maxage=456', $response->headers->get('Cache-Control')); + $this->assertSame('max-age=123, public, s-maxage=456, stale-if-error=70, stale-while-revalidate=928', $response->headers->get('Cache-Control')); $this->assertSame(['Vary-1', 'Vary-2'], $response->getVary()); } }