@@ -37,6 +37,7 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
37
37
private int $ embeddedResponses = 0 ;
38
38
private bool $ isNotCacheableResponseEmbedded = false ;
39
39
private int $ age = 0 ;
40
+ private \DateTimeInterface |null |false $ lastModified = null ;
40
41
private array $ flagDirectives = [
41
42
'no-cache ' => null ,
42
43
'no-store ' => null ,
@@ -90,6 +91,11 @@ public function add(Response $response)
90
91
$ expires = $ response ->getExpires ();
91
92
$ expires = null !== $ expires ? (int ) $ expires ->format ('U ' ) - (int ) $ response ->getDate ()->format ('U ' ) : null ;
92
93
$ this ->storeRelativeAgeDirective ('expires ' , $ expires >= 0 ? $ expires : null , 0 , $ isHeuristicallyCacheable );
94
+
95
+ if (false !== $ this ->lastModified ) {
96
+ $ lastModified = $ response ->getLastModified ();
97
+ $ this ->lastModified = $ lastModified ? max ($ this ->lastModified , $ lastModified ) : false ;
98
+ }
93
99
}
94
100
95
101
/**
@@ -102,17 +108,16 @@ public function update(Response $response)
102
108
return ;
103
109
}
104
110
105
- // Remove validation related headers of the master response,
106
- // because some of the response content comes from at least
107
- // one embedded response (which likely has a different caching strategy).
111
+ // Remove Etag since it cannot be merged from embedded responses.
108
112
$ response ->setEtag (null );
109
- $ response ->setLastModified (null );
110
113
111
114
$ this ->add ($ response );
112
115
113
116
$ response ->headers ->set ('Age ' , $ this ->age );
114
117
115
118
if ($ this ->isNotCacheableResponseEmbedded ) {
119
+ $ response ->setLastModified ();
120
+
116
121
if ($ this ->flagDirectives ['no-store ' ]) {
117
122
$ response ->headers ->set ('Cache-Control ' , 'no-cache, no-store, must-revalidate ' );
118
123
} else {
@@ -122,6 +127,8 @@ public function update(Response $response)
122
127
return ;
123
128
}
124
129
130
+ $ response ->setLastModified ($ this ->lastModified ?: null );
131
+
125
132
$ flags = array_filter ($ this ->flagDirectives );
126
133
127
134
if (isset ($ flags ['must-revalidate ' ])) {
@@ -162,17 +169,14 @@ private function willMakeFinalResponseUncacheable(Response $response): bool
162
169
// RFC2616: A response received with a status code of 200, 203, 300, 301 or 410
163
170
// MAY be stored by a cache […] unless a cache-control directive prohibits caching.
164
171
if ($ response ->headers ->hasCacheControlDirective ('no-cache ' )
165
- || $ response ->headers ->getCacheControlDirective ('no-store ' )
172
+ || $ response ->headers ->hasCacheControlDirective ('no-store ' )
166
173
) {
167
174
return true ;
168
175
}
169
176
170
- // Last-Modified and Etag headers cannot be merged, they render the response uncacheable
177
+ // Etag headers cannot be merged, they render the response uncacheable
171
178
// by default (except if the response also has max-age etc.).
172
- if (\in_array ($ response ->getStatusCode (), [200 , 203 , 300 , 301 , 410 ])
173
- && null === $ response ->getLastModified ()
174
- && null === $ response ->getEtag ()
175
- ) {
179
+ if (null === $ response ->getEtag () && \in_array ($ response ->getStatusCode (), [200 , 203 , 300 , 301 , 410 ])) {
176
180
return false ;
177
181
}
178
182
0 commit comments