From 689425ba593c073b7313dcae7846b3c34d81ebe6 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 12:30:21 +0100 Subject: [PATCH 1/5] Add new isExpirable() method and consider s-maxage=0 cacheable --- .../Component/HttpFoundation/Response.php | 15 ++++++++++- .../HttpFoundation/Tests/ResponseTest.php | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 9d112d15785d0..94cd611439468 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -530,7 +530,7 @@ public function isCacheable() return false; } - return $this->isValidateable() || $this->isFresh(); + return $this->isValidateable() || $this->isExpirable(); } /** @@ -547,6 +547,19 @@ public function isFresh() return $this->getTtl() > 0; } + /** + * Returns true if the response includes headers that indicate time-based + * content expiration. + * + * @return bool true if the response expires when it reaches a particular age, false otherwise. + */ + public function isExpirable() + { + return $this->headers->hasCacheControlDirective('s-maxage') + || $this->headers->hasCacheControlDirective('max-age') + || $this->headers->has('expires'); + } + /** * Returns true if the response includes headers that can be used to validate * the response with the origin server using a conditional GET request. diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index d73dd3d344c3f..e4b7ebdc4671f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -258,6 +258,24 @@ public function testIsValidateable() $this->assertFalse($response->isValidateable(), '->isValidateable() returns false when no validator is present'); } + public function testIsExpirable() + { + $response = new Response('', 200); + $response->setSharedMaxAge(100); + $this->assertTrue($response->isExpirable(), '->isExpirable() returns true if a shared-maxage is set'); + + $response = new Response('', 200); + $response->setMaxAge(100); + $this->assertTrue($response->isExpirable(), '->isExpirable() returns true if a maxage is set'); + + $response = new Response('', 200); + $response->setExpires($this->createDateTimeOneHourLater()); + $this->assertTrue($response->isExpirable(), '->isExpirable() returns true if an Expires date present'); + + $response = new Response(); + $this->assertFalse($response->isExpirable(), '->isExpirable() returns false when no max-age or expire date is present'); + } + public function testGetDate() { $oneHourAgo = $this->createDateTimeOneHourAgo(); @@ -304,6 +322,14 @@ public function testGetMaxAge() $this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available'); } + public function testMaxAge0IsStillCacheable() + { + $response = new Response(); + $response->setSharedMaxAge(0); + + $this->assertTrue($response->isCacheable(), '->isCacheable() returns true even if the Response must always be revalidated'); + } + public function testSetSharedMaxAge() { $response = new Response(); From 2d939c9136dde2d74c3f18983f0debef3ed65bbd Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 14:39:06 +0100 Subject: [PATCH 2/5] New test: Response with s-maxage=0 can be cached, but must be revalidated --- .../Tests/HttpCache/HttpCacheTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 7751f6e0ccfdc..6ca31eb2f5733 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -586,6 +586,27 @@ public function testHitsCachedResponseWithSMaxAgeDirective() $this->assertEquals('Hello World', $this->response->getContent()); } + public function testCachesResponseWithSMaxAge0ButRevalidatesIt() + { + $this->setNextResponse(200, array('Cache-Control' => 's-maxage=0'), 'Hello World'); + + $this->request('GET', '/'); + $this->assertHttpKernelIsCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertTraceContains('miss'); + $this->assertTraceContains('store'); + $this->assertEquals('Hello World', $this->response->getContent()); + + $this->setNextResponse(304, array('Cache-Control' => 's-maxage=0')); + + $this->request('GET', '/'); + $this->assertHttpKernelIsCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertTraceContains('stale'); + $this->assertTraceContains('valid'); + $this->assertEquals('Hello World', $this->response->getContent()); + } + public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation() { $this->setNextResponse(); From 6c81c7bbc12c9639dc8516c37f6df4ff2f9fa4fd Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 14:41:58 +0100 Subject: [PATCH 3/5] Also make sure the Age is 0 after revalidation --- .../Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php | 4 ++++ .../HttpKernel/Tests/HttpCache/HttpCacheTestCase.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 6ca31eb2f5733..6c6b9b157f336 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -595,8 +595,11 @@ public function testCachesResponseWithSMaxAge0ButRevalidatesIt() $this->assertEquals(200, $this->response->getStatusCode()); $this->assertTraceContains('miss'); $this->assertTraceContains('store'); + $this->assertEquals(0, $this->response->getAge()); $this->assertEquals('Hello World', $this->response->getContent()); + sleep(2); + $this->setNextResponse(304, array('Cache-Control' => 's-maxage=0')); $this->request('GET', '/'); @@ -604,6 +607,7 @@ public function testCachesResponseWithSMaxAge0ButRevalidatesIt() $this->assertEquals(200, $this->response->getStatusCode()); $this->assertTraceContains('stale'); $this->assertTraceContains('valid'); + $this->assertEquals(0, $this->response->getAge()); $this->assertEquals('Hello World', $this->response->getContent()); } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php index 96a66771a06bc..7ab77948510a5 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpCache\Esi; use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\Store; @@ -25,6 +26,8 @@ class HttpCacheTestCase extends TestCase protected $caches; protected $cacheConfig; protected $request; + + /** @var Response */ protected $response; protected $responses; protected $catch; From cf06544fe2990b50688529354d16dbbcec158014 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 14:45:30 +0100 Subject: [PATCH 4/5] fabbot.io --- .../Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php index 7ab77948510a5..a4aa15bc664d4 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php @@ -27,7 +27,7 @@ class HttpCacheTestCase extends TestCase protected $cacheConfig; protected $request; - /** @var Response */ + /** @var Response */ protected $response; protected $responses; protected $catch; From ca37151ef0b3b3575fc3c78012eaea9c0a3f757c Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 17:40:52 +0100 Subject: [PATCH 5/5] Bump dependency --- src/Symfony/Component/HttpKernel/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 14a36bbd4a283..b9a1a5f235133 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.9", "symfony/event-dispatcher": "^2.6.7|~3.0.0", - "symfony/http-foundation": "~2.7.20|~2.8.13|~3.1.6", + "symfony/http-foundation": "^2.8.19|~3.1.6", "symfony/debug": "^2.6.2", "psr/log": "~1.0" },