Skip to content

Commit 3a21418

Browse files
committed
Merge pull request #151 from FriendsOfSymfony/gv-allow-cache-overwrite
Allow override of request cache headers
2 parents 7321b95 + 233420c commit 3a21418

File tree

11 files changed

+178
-42
lines changed

11 files changed

+178
-42
lines changed

DependencyInjection/Configuration.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ private function addCacheControlSection(ArrayNodeDefinition $rootNode)
148148
->arrayNode('cache_control')
149149
->fixXmlConfig('rule')
150150
->children()
151+
->arrayNode('defaults')
152+
->addDefaultsIfNotSet()
153+
->children()
154+
->booleanNode('overwrite')
155+
->info('Whether to overwrite existing cache headers')
156+
->defaultFalse()
157+
->end()
158+
->end()
159+
->end()
151160
->arrayNode('rules')
152161
->prototype('array')
153162
->children();
@@ -158,6 +167,11 @@ private function addCacheControlSection(ArrayNodeDefinition $rootNode)
158167
->isRequired()
159168
// todo validate there is some header defined
160169
->children()
170+
->enumNode('overwrite')
171+
->info('Whether to overwrite cache headers for this rule, defaults to the cache_control.defaults.overwrite setting')
172+
->values(array('default', true, false))
173+
->defaultValue('default')
174+
->end()
161175
->arrayNode('cache_control')
162176
->info('Add the specified cache control directives.')
163177
->children()

DependencyInjection/FOSHttpCacheExtension.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,12 @@ private function loadCacheControl(ContainerBuilder $container, array $config)
108108

109109
foreach ($config['rules'] as $rule) {
110110
$ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
111-
$controlDefinition->addMethodCall('addRule', array($ruleMatcher, $rule['headers']))
112-
;
111+
112+
if ('default' === $rule['headers']['overwrite']) {
113+
$rule['headers']['overwrite'] = $config['defaults']['overwrite'];
114+
}
115+
116+
$controlDefinition->addMethodCall('addRule', array($ruleMatcher, $rule['headers']));
113117
}
114118
}
115119

EventListener/CacheControlSubscriber.php

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ public function onKernelResponse(FilterResponseEvent $event)
112112
$directives = array_intersect_key($options['cache_control'], $this->supportedDirectives);
113113
$extraDirectives = array_diff_key($options['cache_control'], $directives);
114114
if (!empty($directives)) {
115-
$this->setCache($response, $directives);
115+
$this->setCache($response, $directives, $options['overwrite']);
116116
}
117117
if (!empty($extraDirectives)) {
118-
$this->setExtraCacheDirectives($response, $extraDirectives);
118+
$this->setExtraCacheDirectives($response, $extraDirectives, $options['overwrite']);
119119
}
120120
}
121121

@@ -127,17 +127,32 @@ public function onKernelResponse(FilterResponseEvent $event)
127127
}
128128

129129
if (!empty($options['vary'])) {
130-
$response->setVary(array_merge($response->getVary(), $options['vary']), true); //update if already has vary
130+
$response->setVary($options['vary'], $options['overwrite']);
131131
}
132132

133-
if (isset($options['last_modified']) && null === $response->getLastModified()) {
133+
if (isset($options['last_modified'])
134+
&& ($options['overwrite'] || null === $response->getLastModified())
135+
) {
134136
$response->setLastModified(new \DateTime($options['last_modified']));
135137
}
136138
}
137139
}
138140

139-
private function setCache(Response $response, array $directives)
141+
/**
142+
* Set cache headers on response.
143+
*
144+
* @param Response $response
145+
* @param array $directives
146+
* @param boolean $overwrite Whether to keep existing cache headers or to overwrite them.
147+
*/
148+
private function setCache(Response $response, array $directives, $overwrite)
140149
{
150+
if ($overwrite) {
151+
$response->setCache($directives);
152+
153+
return;
154+
}
155+
141156
if ('no-cache' === $response->headers->get('cache-control')) {
142157
// this single header is set by default. if its the only thing, we override it.
143158
$response->setCache($directives);
@@ -165,16 +180,17 @@ private function setCache(Response $response, array $directives)
165180
*
166181
* @param Response $response
167182
* @param array $controls
183+
* @param boolean $overwrite Whether to keep existing cache headers or to overwrite them.
168184
*/
169-
private function setExtraCacheDirectives(Response $response, array $controls)
185+
private function setExtraCacheDirectives(Response $response, array $controls, $overwrite)
170186
{
171187
$flags = array('must_revalidate', 'proxy_revalidate', 'no_transform', 'no_cache');
172188
$options = array('stale_if_error', 'stale_while_revalidate');
173189

174190
foreach ($flags as $key) {
175191
$flag = str_replace('_', '-', $key);
176192
if (!empty($controls[$key])
177-
&& !$response->headers->hasCacheControlDirective($flag)
193+
&& ($overwrite || !$response->headers->hasCacheControlDirective($flag))
178194
) {
179195
$response->headers->addCacheControlDirective($flag);
180196
}
@@ -183,9 +199,10 @@ private function setExtraCacheDirectives(Response $response, array $controls)
183199
foreach ($options as $key) {
184200
$option = str_replace('_', '-', $key);
185201
if (isset($controls[$key])
186-
&& !$response->headers->hasCacheControlDirective($option)
202+
&& ($overwrite || !$response->headers->hasCacheControlDirective($option))
187203
) {
188204
$response->headers->addCacheControlDirective($option, $controls[$key]);
205+
189206
}
190207
}
191208
}

Resources/doc/features/headers.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ Set caching headers under the ``cache_control`` configuration section,
1111
which consists of a set of rules. When the request matches all criteria under
1212
``match``, the headers under ``headers`` will be set on the response.
1313

14+
A Response may already have cache headers set, e.g. by the controller method.
15+
By default, the options that already exist are not overwritten, but additional
16+
headers are added. You can force to overwrite the headers globally by setting
17+
``cache_control.defaults.overwrite: true`` to true, or on a per rule basis with
18+
``overwrite: true`` under ``headers``.
19+
1420
For instance:
1521

1622
.. code-block:: yaml
1723
1824
# app/config/config.yml
1925
fos_http_cache:
2026
cache_control:
27+
defaults:
28+
overwrite: true
2129
rules:
2230
# only match login.example.com
2331
-
@@ -48,8 +56,9 @@ For instance:
4856
# match everything to set defaults
4957
-
5058
match:
51-
path: ^/
59+
path: ^/
5260
headers:
61+
overwrite: false
5362
cache_control: { public: true, max_age: 15, s_maxage: 30 }
5463
last_modified: "-1 hour"
5564

Resources/doc/reference/configuration/headers.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,23 @@ parameters described in the ``match`` section, the headers as defined under
66
``headers`` will be set on the response, if they are not already set. Rules are
77
checked in the order specified, where the first match wins.
88

9+
A global setting and a per rule ``overwrite`` option allow to overwrite the
10+
cache headers even if they are already set.
11+
912
.. code-block:: yaml
1013
1114
# app/config/config.yml
1215
fos_http_cache:
1316
cache_control:
17+
defaults:
18+
overwrite: false
1419
rules:
1520
# only match login.example.com
1621
-
1722
match:
1823
host: ^login.example.com$
1924
headers:
25+
overwrite: true
2026
cache_control:
2127
public: false
2228
max_age: 0

Tests/Resources/Fixtures/config/full.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
$container->loadFromExtension('fos_http_cache', array(
44
'cache_control' => array(
5+
'defaults' => array(
6+
'overwrite' => true
7+
),
58
'rules' => array(
69
array(
710
'match' => array(
@@ -13,6 +16,7 @@
1316
'additional_cacheable_status' => array(100, 500),
1417
),
1518
'headers' => array(
19+
'overwrite' => false,
1620
'cache_control' => array(
1721
'max_age' => 1,
1822
's_maxage' => 2,

Tests/Resources/Fixtures/config/full.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
<config xmlns="http://example.org/schema/dic/fos_http_cache">
55
<cache-control>
6+
<defaults>
7+
<overwrite>true</overwrite>
8+
</defaults>
69
<rule>
710
<match
811
path="/abc"
@@ -17,6 +20,7 @@
1720
<additional-cacheable-status>500</additional-cacheable-status>
1821
</match>
1922
<headers last-modified="-1 hour" reverse-proxy-ttl="42">
23+
<overwrite>false</overwrite>
2024
<cache-control
2125
max-age="1"
2226
s-maxage="2"

Tests/Resources/Fixtures/config/full.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
fos_http_cache:
22

33
cache_control:
4+
defaults:
5+
overwrite: true
46
rules:
57
-
68
match:
@@ -18,6 +20,7 @@ fos_http_cache:
1820
- 100
1921
- 500
2022
headers:
23+
overwrite: false
2124
cache_control:
2225
max_age: 1
2326
s_maxage: 2

Tests/Unit/DependencyInjection/ConfigurationTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public function testSupportsAllConfigFormats()
4949
{
5050
$expectedConfiguration = array(
5151
'cache_control' => array(
52+
'defaults' => array(
53+
'overwrite' => true,
54+
),
5255
'rules' => array(
5356
array(
5457
'match' => array(
@@ -62,6 +65,7 @@ public function testSupportsAllConfigFormats()
6265
// TODO 'match_response' => '',
6366
),
6467
'headers' => array(
68+
'overwrite' => false,
6569
'cache_control' => array(
6670
'max_age' => 1,
6771
's_maxage' => 2,
@@ -220,9 +224,13 @@ public function testSplitOptions()
220224
'headers' => array(
221225
'reverse_proxy_ttl' => null,
222226
'vary' => array('Cookie', 'Authorization'),
227+
'overwrite' => 'default',
223228
),
224229
),
225230
),
231+
'defaults' => array(
232+
'overwrite' => false,
233+
),
226234
);
227235
$expectedConfiguration['proxy_client'] = array(
228236
'varnish' => array(

0 commit comments

Comments
 (0)