Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d8bbeb1

Browse filesBrowse files
committed
Make strict s-maxage compliance (implies proxy-revalidate) a config option, defaulting to false
1 parent ff61037 commit d8bbeb1
Copy full SHA for d8bbeb1

File tree

2 files changed

+42
-1
lines changed
Filter options

2 files changed

+42
-1
lines changed

‎src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+13-1Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
6969
* the cache can serve a stale response when an error is encountered (default: 60).
7070
* This setting is overridden by the stale-if-error HTTP Cache-Control extension
7171
* (see RFC 5861).
72+
*
73+
* * strict_smaxage RFC 7234 Section 5.2.2.9 (https://tools.ietf.org/html/rfc7234#section-5.2.2.9)
74+
* mandates that `s-maxage` implies `proxy-revalidate`. This means that when `s-maxage`
75+
* is present on a Response, it must not be served stale. This prohibits the `stale-if-error`
76+
* behavior for such responses, greatly reducing the benefit of that feature.
77+
* Since Symfony for a long time encouraged the use of `s-maxage` and treated it like a
78+
* short form of `public, maxage=...` (without obeying this RFC peculiarity), this configuration
79+
* switch can be used to ignore these extra semantics.
80+
* When set to `false` (the default value), responses with `s-maxage` _may_ be served stale
81+
* when the backend returns an 5xx error on revalidation. Set this to `true` for strict
82+
* compliance with Sections 5.2.2.9 and 4.2.4 of RFC 7234.
7283
*/
7384
public function __construct(HttpKernelInterface $kernel, StoreInterface $store, SurrogateInterface $surrogate = null, array $options = [])
7485
{
@@ -87,6 +98,7 @@ public function __construct(HttpKernelInterface $kernel, StoreInterface $store,
8798
'allow_revalidate' => false,
8899
'stale_while_revalidate' => 2,
89100
'stale_if_error' => 60,
101+
'strict_smaxage' => false,
90102
], $options);
91103
}
92104

@@ -469,7 +481,7 @@ protected function forward(Request $request, $catch = false, Response $entry = n
469481
&& \in_array($response->getStatusCode(), [500, 502, 503, 504])
470482
&& !$entry->headers->hasCacheControlDirective('no-cache')
471483
&& !$entry->mustRevalidate()
472-
&& !$entry->headers->hasCacheControlDirective('s-maxage')
484+
&& (!$this->options['strict_smaxage'] || !$entry->headers->hasCacheControlDirective('s-maxage'))
473485
) {
474486
if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) {
475487
$age = $this->options['stale_if_error'];

‎src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,7 @@ public function testResponsesThatMustNotBeUsedStaleIfError($responseHeaders, $sl
16271627

16281628
$this->setNextResponses($responses);
16291629
$this->cacheConfig['stale_if_error'] = 10; // after stale, may be served for 10s
1630+
$this->cacheConfig['strict_smaxage'] = true; // full RFC compliance for this feature
16301631

16311632
$this->request('GET', '/'); // warm cache
16321633

@@ -1656,6 +1657,34 @@ public function getResponseDataThatMustNotBeServedStaleIfError()
16561657
yield 'must-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, must-revalidate'], 15];
16571658
yield 'proxy-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, proxy-revalidate'], 15];
16581659
}
1660+
1661+
public function testStaleIfErrorWhenStrictSmaxageDisabled()
1662+
{
1663+
$responses = [
1664+
[
1665+
'status' => 200,
1666+
'body' => 'OK',
1667+
'headers' => ['Cache-Control' => 'public, s-maxage=20'],
1668+
],
1669+
[
1670+
'status' => 500,
1671+
'body' => 'FAIL',
1672+
'headers' => [],
1673+
],
1674+
];
1675+
1676+
$this->setNextResponses($responses);
1677+
$this->cacheConfig['stale_if_error'] = 10;
1678+
$this->cacheConfig['strict_smaxage'] = false;
1679+
1680+
$this->request('GET', '/'); // warm cache
1681+
sleep(25);
1682+
$this->request('GET', '/'); // hit backend error
1683+
1684+
$this->assertEquals(200, $this->response->getStatusCode());
1685+
$this->assertEquals('OK', $this->response->getContent());
1686+
$this->assertTraceContains('stale-if-error');
1687+
}
16591688
}
16601689

16611690
class TestKernel implements HttpKernelInterface

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.