Commit fb6c562c authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2263981 by znerol, beejeebus: Introduce a robust and extensible page cache-policy framework.

parent 1476c56c
Loading
Loading
Loading
Loading
+13 −1
Changes for core/core.services.yml: 13 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -100,6 +100,18 @@ services:
    factory_method: get
    factory_service: cache_factory
    arguments: [discovery]
  page_cache_request_policy:
    class: Drupal\Core\PageCache\DefaultRequestPolicy
    tags:
      - { name: service_collector, tag: page_cache_request_policy, call: addPolicy}
  page_cache_response_policy:
    class: Drupal\Core\PageCache\ChainResponsePolicy
    tags:
      - { name: service_collector, tag: page_cache_response_policy, call: addPolicy}
  page_cache_kill_switch:
    class: Drupal\Core\PageCache\ResponsePolicy\KillSwitch
    tags:
      - { name: page_cache_response_policy }
  config.manager:
    class: Drupal\Core\Config\ConfigManager
    arguments: ['@entity.manager', '@config.factory', '@config.typed', '@string_translation', '@config.storage', '@event_dispatcher']
@@ -729,7 +741,7 @@ services:
    class: Drupal\Core\EventSubscriber\FinishResponseSubscriber
    tags:
      - { name: event_subscriber }
    arguments: ['@language_manager', '@config.factory']
    arguments: ['@language_manager', '@config.factory', '@page_cache_request_policy', '@page_cache_response_policy']
  redirect_response_subscriber:
    class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber
    arguments: ['@url_generator']
+1 −25
Changes for core/includes/bootstrap.inc: 1 added line, 25 removed lines.
Original line number Diff line number Diff line
@@ -389,30 +389,6 @@ function drupal_page_get_cache(Request $request) {
  }
}

/**
 * Determines the cacheability of the current page.
 *
 * Note: we do not serve cached pages to authenticated users, or to anonymous
 * users when $_SESSION is non-empty. $_SESSION may contain status messages
 * from a form submission, the contents of a shopping cart, or other user-
 * specific content that should not be cached and displayed to other users.
 *
 * @param $allow_caching
 *   Set to FALSE if you want to prevent this page to get cached.
 *
 * @return
 *   TRUE if the current page can be cached, FALSE otherwise.
 */
function drupal_page_is_cacheable($allow_caching = NULL) {
  $allow_caching_static = &drupal_static(__FUNCTION__, TRUE);
  if (isset($allow_caching)) {
    $allow_caching_static = $allow_caching;
  }

  return $allow_caching_static && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')
    && PHP_SAPI !== 'cli';
}

/**
 * Sets an HTTP response header for the current page.
 *
@@ -931,7 +907,7 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
    }

    // Mark this page as being uncacheable.
    drupal_page_is_cacheable(FALSE);
    \Drupal::service('page_cache_kill_switch')->trigger();
  }

  // Messages not set when DB connection fails.
+2 −2
Changes for core/includes/utility.inc: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -62,8 +62,8 @@ function drupal_rebuild(ClassLoader $classloader, Request $request) {
    $bin->deleteAll();
  }

  // Disable the page cache.
  drupal_page_is_cacheable(FALSE);
  // Disable recording of cached pages.
  \Drupal::service('page_cache_kill_switch')->trigger();

  drupal_flush_all_caches();

+3 −3
Changes for core/lib/Drupal/Core/DrupalKernel.php: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
use Drupal\Core\DependencyInjection\YamlFileLoader;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Language\Language;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Site\Settings;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -466,9 +467,8 @@ public function handlePageCache(Request $request) {
      $cache_enabled = $config->get('cache.page.use_internal');
    }

    // If there is no session cookie and cache is enabled (or forced), try to
    // serve a cached page.
    if (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) {
    $request_policy = \Drupal::service('page_cache_request_policy');
    if ($cache_enabled && $request_policy->check($request) === RequestPolicyInterface::ALLOW) {
      // Get the page from the cache.
      $response = drupal_page_get_cache($request);
      // If there is a cached page, display it.
+29 −2
Changes for core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php: 29 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\PageCache\RequestPolicyInterface;
use Drupal\Core\PageCache\ResponsePolicyInterface;
use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -40,6 +42,20 @@ class FinishResponseSubscriber implements EventSubscriberInterface {
   */
  protected $config;

  /**
   * A policy rule determining the cacheability of a request.
   *
   * @var \Drupal\Core\PageCache\RequestPolicyInterface
   */
  protected $requestPolicy;

  /**
   * A policy rule determining the cacheability of the response.
   *
   * @var \Drupal\Core\PageCache\ResponsePolicyInterface
   */
  protected $responsePolicy;

  /**
   * Constructs a FinishResponseSubscriber object.
   *
@@ -47,10 +63,16 @@ class FinishResponseSubscriber implements EventSubscriberInterface {
   *   The language manager object for retrieving the correct language code.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   A config factory for retrieving required config objects.
   * @param \Drupal\Core\PageCache\RequestPolicyInterface $request_policy
   *   A policy rule determining the cacheability of a request.
   * @param \Drupal\Core\PageCache\ResponsePolicyInterface $response_policy
   *   A policy rule determining the cacheability of a response.
   */
  public function __construct(LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory) {
  public function __construct(LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory, RequestPolicyInterface $request_policy, ResponsePolicyInterface $response_policy) {
    $this->languageManager = $language_manager;
    $this->config = $config_factory->get('system.performance');
    $this->requestPolicy = $request_policy;
    $this->responsePolicy = $response_policy;
  }

  /**
@@ -83,16 +105,21 @@ public function onRespond(FilterResponseEvent $event) {
      $response->headers->set($name, $value, FALSE);
    }

    $is_cacheable = drupal_page_is_cacheable();
    $is_cacheable = ($this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW) && ($this->responsePolicy->check($response, $request) !== ResponsePolicyInterface::DENY);

    // Add headers necessary to specify whether the response should be cached by
    // proxies and/or the browser.
    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);
      }
    }
    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);
    }

Loading