diff -u b/core/modules/page_cache/src/StackMiddleware/PageCache.php b/core/modules/page_cache/src/StackMiddleware/PageCache.php --- b/core/modules/page_cache/src/StackMiddleware/PageCache.php +++ b/core/modules/page_cache/src/StackMiddleware/PageCache.php @@ -7,7 +7,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\PageCache\RequestPolicyInterface; use Drupal\Core\PageCache\ResponsePolicyInterface; -use Drupal\Core\Site\Settings +use Drupal\Core\Site\Settings; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -249,10 +249,30 @@ // - Get the time expiration from the Expires header, rather than the // interface, but see https://www.drupal.org/node/2352009 about possibly // changing that. - $tags = $response->getCacheableMetadata()->getCacheTags(); - $date = $response->getExpires()->getTimestamp(); - $expire = ($date > time()) ? $date : Cache::PERMANENT; - $this->set($request, $response, $expire, $tags); + $expire = FALSE; + // 404 responses can fill non-LRU cache backends and generally are likely to + // have a low cache hit rate. So do not cache them permanently. + if ($response->getStatusCode() === $response::HTTP_NOT_FOUND) { + // Cache for an hour by default, or the max age, whichever is the smaller. + // If the ttl is set to FALSE then do not cache it. + $settings_ttl = Settings::get('404_cache_ttl', 3600); + if ($settings_ttl) { + $max_age = $response->getMaxAge(); + // The response's max_age will be negative in the case the response has + // no time set. + $ttl = ($max_age > 0) ? min($max_age, $settings_ttl) : $settings_ttl; + $expire = REQUEST_TIME + $ttl; + } + } + else { + $date = $response->getExpires()->getTimestamp(); + $expire = ($date > time()) ? $date : Cache::PERMANENT; + } + + if ($expire !== FALSE) { + $tags = $response->getCacheableMetadata()->getCacheTags(); + $this->set($request, $response, $expire, $tags); + } // Mark response as a cache miss. $response->headers->set('X-Drupal-Cache', 'MISS'); @@ -308,17 +328,6 @@ */ protected function set(Request $request, Response $response, $expire, array $tags) { $cid = $this->getCacheId($request); - - // 404 responses can fill non-LRU cache backends and generally are likely to - // have a low cache hit rate. So do not cache them permanently. - if ($response->getStatusCode() == $response::HTTP_NOT_FOUND) { - $max_age = $response->getMaxAge(); - - // Cache for an hour by default, or the max age, whichever is the greater. - $ttl = Settings::get('404_cache_ttl', 3600); - $expire = REQUEST_TIME + min($max_age, $ttl); - } - $this->cache->set($cid, $response, $expire, $tags); } only in patch2: unchanged: --- a/core/modules/page_cache/src/Tests/PageCacheTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTest.php @@ -375,6 +375,21 @@ function testPageCacheAnonymous403404() { $this->assertResponse($code); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); } + + // Disable 404 caching + $settings['settings']['404_cache_ttl'] = (object) array( + 'value' => FALSE, + 'required' => TRUE, + ); + $this->writeSettings($settings); + \Drupal::service('cache.render')->deleteAll(); + + // Getting the 404 page twice you still result in a cache miss. + $this->drupalGet($invalid_url); + $this->drupalGet($invalid_url); + $this->assertResponse(404); + $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); + } /**