diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
index 184666978cf42..6ffe8890571b6 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
@@ -237,7 +237,9 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R
$response->prepare($request);
- $response->isNotModified($request);
+ if (HttpKernelInterface::MAIN_REQUEST === $type) {
+ $response->isNotModified($request);
+ }
return $response;
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
index 1f63686053d51..915af2f35f07f 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
@@ -1329,6 +1329,175 @@ public function testEsiCacheSendsTheLowestTtlForHeadRequests()
$this->assertEquals(100, $this->response->getTtl());
}
+ public function testEsiCacheIncludesEmbeddedResponseContentWhenMainResponseFailsRevalidationAndEmbeddedResponseIsFresh()
+ {
+ $this->setNextResponses([
+ [
+ 'status' => 200,
+ 'body' => 'main ',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0', // goes stale immediately
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',
+ ],
+ ],
+ [
+ 'status' => 200,
+ 'body' => 'embedded',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=10', // stays fresh
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',
+ ]
+ ],
+ ]);
+
+ // prime the cache
+ $this->request('GET', '/', [], [], true);
+ $this->assertSame(200, $this->response->getStatusCode());
+ $this->assertSame('main embedded', $this->response->getContent());
+ $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\DATE_RFC2822)); // max of both values
+
+ $this->setNextResponses([
+ [
+ // On the next request, the main response has an updated Last-Modified (main page was modified)...
+ 'status' => 200,
+ 'body' => 'main ',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0',
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:10:00 +0000',
+ ],
+ ],
+ // no revalidation request happens for the embedded response, since it is still fresh
+ ]);
+
+ // Re-request with Last-Modified time that we received when the cache was primed
+ $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:05:00 +0000'], [], true);
+
+ $this->assertSame(200, $this->response->getStatusCode());
+
+ // The cache should use the content ("embedded") from the cached entry
+ $this->assertSame('main embedded', $this->response->getContent());
+
+ $traces = $this->cache->getTraces();
+ $this->assertSame(['stale', 'invalid', 'store'], $traces['GET /']);
+
+ // The embedded resource was still fresh
+ $this->assertSame(['fresh'], $traces['GET /foo']);
+ }
+
+ public function testEsiCacheIncludesEmbeddedResponseContentWhenMainResponseFailsRevalidationAndEmbeddedResponseIsValid()
+ {
+ $this->setNextResponses([
+ [
+ 'status' => 200,
+ 'body' => 'main ',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0', // goes stale immediately
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',
+ ],
+ ],
+ [
+ 'status' => 200,
+ 'body' => 'embedded',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0', // goes stale immediately
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',
+ ]
+ ],
+ ]);
+
+ // prime the cache
+ $this->request('GET', '/', [], [], true);
+ $this->assertSame(200, $this->response->getStatusCode());
+ $this->assertSame('main embedded', $this->response->getContent());
+ $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\DATE_RFC2822)); // max of both values
+
+ $this->setNextResponses([
+ [
+ // On the next request, the main response has an updated Last-Modified (main page was modified)...
+ 'status' => 200,
+ 'body' => 'main ',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0',
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:10:00 +0000',
+ ],
+ ],
+ [
+ // We have a stale cache entry for the embedded response which will be revalidated.
+ // Let's assume the resource did not change, so the controller sends a 304 without content body.
+ 'status' => 304,
+ 'body' => '',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=0',
+ ],
+ ],
+ ]);
+
+ // Re-request with Last-Modified time that we received when the cache was primed
+ $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:05:00 +0000'], [], true);
+
+ $this->assertSame(200, $this->response->getStatusCode());
+
+ // The cache should use the content ("embedded") from the cached entry
+ $this->assertSame('main embedded', $this->response->getContent());
+
+ $traces = $this->cache->getTraces();
+ $this->assertSame(['stale', 'invalid', 'store'], $traces['GET /']);
+
+ // Check that the embedded resource was successfully revalidated
+ $this->assertSame(['stale', 'valid', 'store'], $traces['GET /foo']);
+ }
+
+ public function testEsiCacheIncludesEmbeddedResponseContentWhenMainAndEmbeddedResponseAreFresh()
+ {
+ $this->setNextResponses([
+ [
+ 'status' => 200,
+ 'body' => 'main ',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=10',
+ 'Surrogate-Control' => 'content="ESI/1.0"',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:05:00 +0000',
+ ],
+ ],
+ [
+ 'status' => 200,
+ 'body' => 'embedded',
+ 'headers' => [
+ 'Cache-Control' => 's-maxage=10',
+ 'Last-Modified' => 'Mon, 12 Aug 2024 10:00:00 +0000',
+ ]
+ ],
+ ]);
+
+ // prime the cache
+ $this->request('GET', '/', [], [], true);
+ $this->assertSame(200, $this->response->getStatusCode());
+ $this->assertSame('main embedded', $this->response->getContent());
+ $this->assertSame('Mon, 12 Aug 2024 10:05:00 +0000', $this->response->getLastModified()->format(\DATE_RFC2822));
+
+ // Assume that a client received 'Mon, 12 Aug 2024 10:00:00 +0000' as last-modified information in the past. This may, for example,
+ // be the case when the "main" response at that point had an older Last-Modified time, so the embedded response's Last-Modified time
+ // governed the result for the combined response. In other words, the client received a Last-Modified time that still validates the
+ // embedded response as of now, but no longer matches the Last-Modified time of the "main" resource.
+ // Now this client does a revalidation request.
+ $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => 'Mon, 12 Aug 2024 10:00:00 +0000'], [], true);
+
+ $this->assertSame(200, $this->response->getStatusCode());
+
+ // The cache should use the content ("embedded") from the cached entry
+ $this->assertSame('main embedded', $this->response->getContent());
+
+ $traces = $this->cache->getTraces();
+ $this->assertSame(['fresh'], $traces['GET /']);
+
+ // Check that the embedded resource was successfully revalidated
+ $this->assertSame(['fresh'], $traces['GET /foo']);
+ }
+
public function testEsiCacheForceValidation()
{
$responses = [
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy