diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index da3a2776847082d9b9ebba9f35d5e4e19254538a..e8dd01144ebadd062dc041ce7db3de2c655fe455 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -950,6 +950,23 @@ function variable_del($name) { unset($conf[$name]); } +/** + * Gets the page cache cid for this request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request for this page. + * + * @return string + * The cid for this request. + */ +function drupal_page_cache_get_cid(Request $request) { + $cid_parts = array( + $request->getUri(), + Drupal::service('content_negotiation')->getContentType($request), + ); + return sha1(implode(':', $cid_parts)); +} + /** * Retrieves the current page from the cache. * @@ -958,27 +975,15 @@ function variable_del($name) { * 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 $check_only - * (optional) Set to TRUE to only return whether a previous call found a - * cache entry. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request for this page. * * @return * The cache object, if the page was found in the cache, NULL otherwise. */ -function drupal_page_get_cache($check_only = FALSE) { - global $base_root; - static $cache_hit = FALSE; - - if ($check_only) { - return $cache_hit; - } - +function drupal_page_get_cache(Request $request) { if (drupal_page_is_cacheable()) { - $cache = cache('page')->get($base_root . request_uri()); - if ($cache !== FALSE) { - $cache_hit = TRUE; - } - return $cache; + return Drupal::cache('page')->get(drupal_page_cache_get_cid($request)); } } @@ -2035,7 +2040,6 @@ function _drupal_bootstrap_page_cache() { $cache_enabled = $config->get('cache.page.use_internal'); } - // @todo this is *criminal*. but, necessary, until we fix bootstrap ordering. $request = Request::createFromGlobals(); // If there is no session cookie and cache is enabled (or forced), try // to serve a cached page. @@ -2043,7 +2047,7 @@ function _drupal_bootstrap_page_cache() { // Make sure there is a user object because its timestamp will be checked. $user = drupal_anonymous_user(); // Get the page from the cache. - $cache = drupal_page_get_cache(); + $cache = drupal_page_get_cache($request); // If there is a cached page, display it. if (is_object($cache)) { $response = new Response(); diff --git a/core/includes/common.inc b/core/includes/common.inc index 842136e28269463f5e18bb37b0764f8392e02710..26181c0a32691fd97f94ee7f63fb069330bb7df8 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3165,11 +3165,9 @@ function _drupal_bootstrap_full($skip = FALSE) { * @see drupal_page_header() */ function drupal_page_set_cache(Response $response, Request $request) { - global $base_root; - if (drupal_page_is_cacheable()) { $cache = (object) array( - 'cid' => $base_root . $request->getRequestUri(), + 'cid' => drupal_page_cache_get_cid($request), 'data' => array( 'path' => $request->attributes->get('_system_path'), 'body' => $response->getContent(), diff --git a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php index ca2d7b3a2b0dec29f7cb879600e2f55fb9aef4f0..3bbc72956119f8543b95b023043b3ec90f3be4b3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Bootstrap; +use Symfony\Component\Routing\RequestContext; use Drupal\simpletest\WebTestBase; /** @@ -40,6 +41,33 @@ function setUp() { ->save(); } + /** + * Tests support for different cache items with different Accept headers. + */ + function testAcceptHeaderRequests() { + $config = config('system.performance'); + $config->set('cache.page.use_internal', 1); + $config->set('cache.page.max_age', 300); + $config->save(); + + $url_generator = \Drupal::urlGenerator(); + $url_generator->setContext(new RequestContext()); + $accept_header_cache_uri = $url_generator->getPathFromRoute('system_test.page_cache_accept_header'); + $json_accept_header = array('Accept: application/json'); + + $this->drupalGet($accept_header_cache_uri); + $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'HTML page was not yet cached.'); + $this->drupalGet($accept_header_cache_uri); + $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'HTML page was cached.'); + $this->assertRaw('<p>oh hai this is html.</p>', 'The correct HTML response was returned.'); + + $this->drupalGet($accept_header_cache_uri, array(), $json_accept_header); + $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Json response was not yet cached.'); + $this->drupalGet($accept_header_cache_uri, array(), $json_accept_header); + $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Json response was cached.'); + $this->assertRaw('{"content":"oh hai this is json"}', 'The correct Json response was returned.'); + } + /** * Tests support of requests with If-Modified-Since and If-None-Match headers. */ diff --git a/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/PageCacheAcceptHeaderController.php b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/PageCacheAcceptHeaderController.php new file mode 100644 index 0000000000000000000000000000000000000000..cc3b23167df4cb70e96906c4380843f06deaa914 --- /dev/null +++ b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/PageCacheAcceptHeaderController.php @@ -0,0 +1,35 @@ +<?php + +/** + * @file + * Contains \Drupal\system_test\Controller\PageCacheAcceptHeaderController. + */ + +namespace Drupal\system_test\Controller; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\JsonResponse; + +/** + * Defines a controller to respond the page cache accept header test. + */ +class PageCacheAcceptHeaderController { + + /** + * Processes a request that will vary with Accept header. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * + * @return mixed + */ + public function content(Request $request) { + if ($request->headers->get('Accept') == 'application/json') { + return new JsonResponse(array('content' => 'oh hai this is json')); + } + else { + return "<p>oh hai this is html.</p>"; + } + } +} + diff --git a/core/modules/system/tests/modules/system_test/system_test.routing.yml b/core/modules/system/tests/modules/system_test/system_test.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..1be2566eba9c8c96d2778cf1cf2a2ef3133268fb --- /dev/null +++ b/core/modules/system/tests/modules/system_test/system_test.routing.yml @@ -0,0 +1,7 @@ +system_test.page_cache_accept_header: + pattern: '/system-test/page-cache/accept-header' + defaults: + _controller: '\Drupal\system_test\Controller\PageCacheAcceptHeaderController::content' + requirements: + _access: 'TRUE' + diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index dbbca14e1cc6f98e67473ef89d1547f053150ee4..f058445b484d406ce79fb46991e5bc969e0eb649 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -125,10 +125,10 @@ function _toolbar_initialize_page_cache() { // If we have a cache, serve it. // @see _drupal_bootstrap_page_cache() - $cache = drupal_page_get_cache(); + $request = \Drupal::request(); + $cache = drupal_page_get_cache($request); if (is_object($cache)) { $response = new Response(); - $request = \Drupal::request(); $response->headers->set('X-Drupal-Cache', 'HIT'); date_default_timezone_set(drupal_get_user_timezone());