core/includes/bootstrap.inc | 13 ++++++----- .../EventSubscriber/FinishResponseSubscriber.php | 26 +++++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 8459d48..a824957 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -899,21 +899,24 @@ function drupal_serve_page_from_cache(Response $response, Request $request) { // Perform HTTP revalidation. $last_modified = $response->getLastModified(); if ($last_modified) { - $created = $last_modified->getTimestamp(); - // See if the client has provided the required HTTP headers. $if_modified_since = $request->server->has('HTTP_IF_MODIFIED_SINCE') ? strtotime($request->server->get('HTTP_IF_MODIFIED_SINCE')) : FALSE; $if_none_match = $request->server->has('HTTP_IF_NONE_MATCH') ? stripslashes($request->server->get('HTTP_IF_NONE_MATCH')) : FALSE; - if ($if_modified_since && $if_modified_since === $created // if-modified-since must match - || $if_none_match && $if_none_match == $response->getEtag()) { // etag must match + $last_modified_match = $if_modified_since === $last_modified->getTimestamp(); + $etag_match = $if_none_match == $response->getEtag(); + + if (($if_modified_since && $if_none_match && $last_modified_match && $etag_match) // If both revalidation request headers are present, apply both. + || ($if_modified_since && !$if_none_match && $last_modified_match) // Only Last-Modified must match. + || ($if_none_match && !$if_modified_since && $etag_match) // Only ETag must match. + ) { $response->setStatusCode(304); $response->setContent(NULL); // In the case of a 304 response, certain headers must be sent, and the // remaining may not (see RFC 2616, section 10.3.5). foreach (array_keys($response->headers->all()) as $name) { - if (!in_array($name, array(/*'content-location', 'expires', 'cache-control', 'vary'))) { + if (!in_array($name, array('etag', 'content-location', 'expires', 'cache-control', 'vary'))) { $response->headers->remove($name); } } diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php index bb6f23a..a96b478 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -92,7 +92,7 @@ public function onRespond(FilterResponseEvent $event) { $this->setResponseNotCacheable($response, $request); } - // Store the response into the internal page cache. + // Store the response in the internal page cache. if ($is_cacheable && $this->config->get('cache.page.use_internal')) { drupal_page_set_cache($response, $request); $response->headers->set('X-Drupal-Cache', 'MISS'); @@ -103,21 +103,23 @@ public function onRespond(FilterResponseEvent $event) { /** * Determine whether the given response has a custom Cache-Control header. * - * Upon construction the ResponseHeaderBag is initialized with an empty + * Upon construction, the ResponseHeaderBag is initialized with an empty * Cache-Control header. Consequently it is not possible to check whether the - * header was set explicitely simply by checking for the presence of it. - * Rather it is necessary to examine the computed Cache-Control header and - * match for results known to be present only when Cache-Control was never set - * explicitely. + * header was set explicitly by simply checking its presence. Instead, it is + * necessary to examine the computed Cache-Control header and compare with + * values known to be present only when Cache-Control was never set + * explicitly. * * When neither Cache-Control nor any of the ETag, Last-Modified, Expires - * headers were set on the response, Cache-Control returns the value - * 'no-cache'. If any of ETag, Last-Modified or Expires was set but not + * headers are set on the response, ::get('cache-control') returns the value + * 'no-cache'. If any of ETag, Last-Modified or Expires are set but not * Cache-Control, then 'private, must-revalidate' (in exactly this order) is * returned. * * @see \Symfony\Component\HttpFoundation\ResponseHeaderBag::computeCacheControlValue() * + * @param \Symfony\Component\HttpFoundation\Response $response + * * @return bool * TRUE when Cache-Control header was set explicitely on the given response. */ @@ -127,7 +129,7 @@ protected function isCacheControlCustomized(Response $response) { } /** - * Add Cache-Control and Expires header for a response which is not cacheable. + * Add Cache-Control and Expires headers to a response which is not cacheable. * * @param \Symfony\Component\HttpFoundation\Response $response * A response object. @@ -140,14 +142,14 @@ protected function setResponseNotCacheable(Response $response, Request $request) // There is no point in sending along headers necessary for cache // revalidation, if caching by proxies and browsers is denied in the first - // place. Therefore remove Etag, Last-Modified and Vary in that case. + // place. Therefore remove ETag, Last-Modified and Vary in that case. $response->setEtag(NULL); $response->setLastModified(NULL); $response->setVary(NULL); } /** - * Add Cache-Control and Expires header to a cacheable response. + * Add Cache-Control and Expires headers to a cacheable response. * * @param \Symfony\Component\HttpFoundation\Response $response * A response object. @@ -189,8 +191,6 @@ protected function setResponseCacheable(Response $response, Request $request) { // fields that fully determines whether a cache is permitted to use the // response to reply to a subsequent request for a given URL without // revalidation. - $has_vary = $response->hasVary(); - $has_omit_vary_cookie = Settings::get('omit_vary_cookie'); if (!$response->hasVary() && !Settings::get('omit_vary_cookie')) { $response->setVary('Cookie', FALSE); }