diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index a1dad99..ef5dd57 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -659,6 +659,32 @@ function drupal_page_get_cache(Request $request) { } /** + * Enable or disable the page cache bootstrap phase. + * + * This is a temporary workaround to make sure that no cached page is delivered + * during a forced cache clear. This will become obsolete as soon as delivery of + * cached pages is removed from the bootstrap. + * See https://www.drupal.org/node/2177461 + * + * @see drupal_rebuild() + * + * @param bool $allow_caching + * (optional) Specify whether the page cache bootstrap phase should be + * executed or not during the next call to drupal_bootstrap(). + * + * @return bool + * TRUE if the page cache bootstrap phase is enabled. + */ +function drupal_bootstrap_page_cache_enable($allow_caching = NULL) { + $allow_caching_static = &drupal_static(__FUNCTION__, TRUE); + if (isset($allow_caching)) { + $allow_caching_static = $allow_caching; + } + + return $allow_caching_static; +} + +/** * Sets an HTTP response header for the current page. * * Note: When sending a Content-Type header, always include a 'charset' type, @@ -1499,26 +1525,8 @@ function _drupal_bootstrap_kernel() { /** * Attempts to serve a page from the cache. - * - * @todo The $disable parameter is a temporary workaround to make sure that - * no cached page is delivered during a forced cache clear. This will become - * obsolete as soon as deliver of cached pages is removed from the bootstrap. - * @see drupal_rebuild() - * - * @param bool $disable - * (Optional) Temporary disable the delivery of cached pages. */ -function _drupal_bootstrap_page_cache($disable = NULL) { - static $disabled = FALSE; - - if (isset($disable)) { - $disabled = $disable; - return; - } - elseif ($disabled) { - return; - } - +function _drupal_bootstrap_page_cache() { require_once __DIR__ . '/database.inc'; // Check for a cache mode force from settings.php. if (Settings::get('page_cache_without_database')) { @@ -1529,6 +1537,14 @@ function _drupal_bootstrap_page_cache($disable = NULL) { $cache_enabled = $config->get('cache.page.use_internal'); } + // This is a temporary workaround to make sure that no cached page is + // delivered during a forced cache clear. This will become obsolete as soon as + // delivery of cached pages is removed from the bootstrap. + // See https://www.drupal.org/node/2177461 + if (!drupal_bootstrap_page_cache_enable()) { + $cache_enabled = FALSE; + } + $request = \Drupal::request(); $request_policy = \Drupal::service('page_cache_request_policy'); if ($cache_enabled && $request_policy->apply($request)) { diff --git a/core/includes/utility.inc b/core/includes/utility.inc index 5dce40a..6dbc490 100644 --- a/core/includes/utility.inc +++ b/core/includes/utility.inc @@ -47,7 +47,7 @@ function drupal_rebuild() { PhpStorageFactory::get('twig')->deleteAll(); // Disable delivery of cached pages. - _drupal_bootstrap_page_cache(TRUE); + drupal_bootstrap_page_cache_enable(FALSE); // Bootstrap up to where caches exist and clear them. drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE); @@ -55,12 +55,12 @@ function drupal_rebuild() { $bin->deleteAll(); } + // Disable recording of cached pages. + \Drupal::service('page_cache_kill_switch')->trigger(); + drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); drupal_flush_all_caches(); - // Restore delivery of cached pages. - _drupal_bootstrap_page_cache(FALSE); - // Restore Drupal's error and exception handlers. // @see _drupal_bootstrap_configuration() set_error_handler('_drupal_error_handler'); diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php index 77af729..d04e59f 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -103,17 +103,21 @@ public function onRespond(FilterResponseEvent $event) { } $is_cacheable = $this->requestPolicy->apply($request) && $this->responsePolicy->apply($response, $request); - $is_customized = $this->isCacheControlCustomized($response); - $is_configured = $this->config->get('cache.page.max_age') > 0; - $response_demands_caching = $is_configured || $is_customized; // Add headers necessary to specify whether the response should be cached by // proxies and/or the browser. - if (!$is_cacheable || !$response_demands_caching) { - $this->setResponseNotCacheable($response, $request); + if ($is_cacheable && $this->config->get('cache.page.max_age') > 0) { + if (!$this->isCacheControlCustomized($response)) { + // Only add the default Cache-Control header if the controller did not + // specify one on the response. + $this->setResponseCacheable($response, $request); + } } - elseif ($is_configured && !$is_customized) { - $this->setResponseCacheable($response, $request); + else { + // If either the policy forbids caching or the sites configuration does + // not allow to add a max-age directive, then enforce a Cache-Control + // header declaring the response as not cacheable. + $this->setResponseNotCacheable($response, $request); } // Store the response in the internal page cache. diff --git a/core/lib/Drupal/Core/PageCache/DefaultRequestPolicy.php b/core/lib/Drupal/Core/PageCache/DefaultRequestPolicy.php index 90b0e50..3f7e846 100644 --- a/core/lib/Drupal/Core/PageCache/DefaultRequestPolicy.php +++ b/core/lib/Drupal/Core/PageCache/DefaultRequestPolicy.php @@ -8,12 +8,16 @@ namespace Drupal\Core\PageCache; /** - * The default request policy. + * The default page cache request policy. + * + * Page caching is denied if either the application is running from the command + * line or the request was not initiated with a safe method (GET or HEAD). Also + * caching is only allowed for requests without a session cookie. */ class DefaultRequestPolicy extends RequestPolicy { /** - * Construct the default request policy. + * Constructs the default page cache request policy. */ public function __construct() { $this->deny(new RequestPolicyRule\CommandLineOrUnsafeMethod()); diff --git a/core/lib/Drupal/Core/PageCache/DefaultResponsePolicy.php b/core/lib/Drupal/Core/PageCache/DefaultResponsePolicy.php index 64b3008..ffdf15f 100644 --- a/core/lib/Drupal/Core/PageCache/DefaultResponsePolicy.php +++ b/core/lib/Drupal/Core/PageCache/DefaultResponsePolicy.php @@ -8,12 +8,17 @@ namespace Drupal\Core\PageCache; /** - * Default response policy. + * The default page cache response policy. + * + * Currently it is not possible to cache some types of responses. Therefore + * exclude binary file responses (generated files, e.g. images with image + * styles) and streamed responses (files directly read from the disk). + * see: https://github.com/symfony/symfony/issues/9128#issuecomment-25088678 */ class DefaultResponsePolicy extends ResponsePolicy { /** - * Construct the default response policy. + * Constructs the default page cache response policy. */ public function __construct() { $this->deny(new ResponsePolicyRule\IsBinaryFileResponse()); diff --git a/core/lib/Drupal/Core/PageCache/RequestPolicyRule/CommandLineOrUnsafeMethod.php b/core/lib/Drupal/Core/PageCache/RequestPolicyRule/CommandLineOrUnsafeMethod.php index 8d86a97..7db44c3 100644 --- a/core/lib/Drupal/Core/PageCache/RequestPolicyRule/CommandLineOrUnsafeMethod.php +++ b/core/lib/Drupal/Core/PageCache/RequestPolicyRule/CommandLineOrUnsafeMethod.php @@ -28,7 +28,7 @@ public function apply(Request $request) { } /** - * Exclude a page request when run from a command line script. + * Indicates whether this is a CLI request. */ protected function isCliRequest(Request $request) { return drupal_is_cli();