diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php index 787b1b1..fdd2a91 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -89,6 +89,19 @@ public function __construct(LanguageManagerInterface $language_manager, ConfigFa } /** + * Sets extra headers on any responses, also subprocess ones. + * + * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event + * The event to process. + */ + public function onAllResponds(FilterResponseEvent $event) { + $response = $event->getResponse(); + // Always add the 'http_response' cache tag to be able to invalidate every + // response. + $response->getCacheableMetadata()->addCacheTags(['http_response']); + } + + /** * Sets extra headers on successful responses. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event @@ -135,17 +148,11 @@ public function onRespond(FilterResponseEvent $event) { return; } - // Always add the 'http_response' cache tag to be able to invalidate every - // response. - $response->getCacheableMetadata()->addCacheTags(['http_response']); - if ($this->debugCacheabilityHeaders) { // Expose the cache contexts and cache tags associated with this page in a // X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header respectively. $response_cacheability = $response->getCacheableMetadata(); - $tags = $response_cacheability->getCacheTags(); - - $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $tags)); + $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $response_cacheability->getCacheTags())); $response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts()))); } @@ -290,6 +297,7 @@ protected function setExpiresNoCache(Response $response) { */ public static function getSubscribedEvents() { $events[KernelEvents::RESPONSE][] = array('onRespond'); + $events[KernelEvents::RESPONSE][] = array('onAllResponds'); return $events; } diff --git a/core/modules/block/src/Tests/BlockTest.php b/core/modules/block/src/Tests/BlockTest.php index 9fd869a..57f4647 100644 --- a/core/modules/block/src/Tests/BlockTest.php +++ b/core/modules/block/src/Tests/BlockTest.php @@ -385,6 +385,7 @@ public function testBlockCacheTags() { 'block_view', 'config:block.block.powered', 'config:user.role.anonymous', + 'http_response', 'rendered', ); sort($expected_cache_tags); @@ -426,6 +427,7 @@ public function testBlockCacheTags() { 'config:block.block.powered', 'config:block.block.powered-2', 'config:user.role.anonymous', + 'http_response', 'rendered', ); sort($expected_cache_tags); diff --git a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php index 3ad4ad1..bba47d5 100644 --- a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php +++ b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php @@ -46,6 +46,7 @@ public function testMenuBlock() { // Verify a cache hit, but also the presence of the correct cache tags. $expected_tags = array( + 'http_response', 'rendered', 'block_view', 'config:block_list', @@ -107,7 +108,7 @@ public function testMenuBlock() { $this->verifyPageCache($url, 'MISS'); // Verify a cache hit. - $this->verifyPageCache($url, 'HIT', ['config:block_list', 'config:user.role.anonymous', 'rendered']); + $this->verifyPageCache($url, 'HIT', ['config:block_list', 'config:user.role.anonymous', 'http_response', 'rendered']); } } diff --git a/core/modules/node/src/Tests/Views/FrontPageTest.php b/core/modules/node/src/Tests/Views/FrontPageTest.php index b27c416..19cb659 100644 --- a/core/modules/node/src/Tests/Views/FrontPageTest.php +++ b/core/modules/node/src/Tests/Views/FrontPageTest.php @@ -265,7 +265,7 @@ protected function doTestFrontPageViewCacheTags($do_assert_views_caches) { $render_cache_tags ); $expected_tags = Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags); - $expected_tags = Cache::mergeTags($expected_tags, ['rendered', 'config:user.role.anonymous', 'config:system.site']); + $expected_tags = Cache::mergeTags($expected_tags, ['http_response', 'rendered', 'config:user.role.anonymous', 'config:system.site']); $this->assertPageCacheContextsAndTags( Url::fromRoute('view.frontpage.page_1'), $cache_contexts, @@ -331,7 +331,7 @@ protected function doTestFrontPageViewCacheTags($do_assert_views_caches) { $this->assertPageCacheContextsAndTags( Url::fromRoute('view.frontpage.page_1'), $cache_contexts, - Cache::mergeTags($first_page_output_cache_tags, ['rendered', 'config:user.role.anonymous']) + Cache::mergeTags($first_page_output_cache_tags, ['http_response', 'rendered', 'config:user.role.anonymous']) ); // Second page. @@ -350,6 +350,7 @@ protected function doTestFrontPageViewCacheTags($do_assert_views_caches) { 'node_view', 'user_view', 'user:0', + 'http_response', 'rendered', // FinishResponseSubscriber adds this cache tag to responses that have the // 'user.permissions' cache context for anonymous users. diff --git a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php index c8db96e..1933457 100644 --- a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php @@ -79,6 +79,7 @@ function testPageCacheTags() { // Full node page 1. $this->assertPageCacheContextsAndTags($node_1->urlInfo(), $cache_contexts, array( + 'http_response', 'rendered', 'block_view', 'config:block_list', @@ -119,6 +120,7 @@ function testPageCacheTags() { // Full node page 2. $this->assertPageCacheContextsAndTags($node_2->urlInfo(), $cache_contexts, array( + 'http_response', 'rendered', 'block_view', 'config:block_list', diff --git a/core/modules/page_cache/src/Tests/PageCacheTest.php b/core/modules/page_cache/src/Tests/PageCacheTest.php index 1ec9282..68f97a3 100644 --- a/core/modules/page_cache/src/Tests/PageCacheTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTest.php @@ -64,6 +64,7 @@ function testPageCacheTags() { $expected_tags = array( 'config:user.role.anonymous', 'pre_render', + 'http_response', 'rendered', 'system_test_cache_tags_page', ); @@ -95,6 +96,7 @@ function testPageCacheTagsIndependentFromCacheabilityHeaders() { $expected_tags = array( 'config:user.role.anonymous', 'pre_render', + 'http_response', 'rendered', 'system_test_cache_tags_page', ); diff --git a/core/modules/search/src/Tests/SearchPageCacheTagsTest.php b/core/modules/search/src/Tests/SearchPageCacheTagsTest.php index 8dabbc7..4937369 100644 --- a/core/modules/search/src/Tests/SearchPageCacheTagsTest.php +++ b/core/modules/search/src/Tests/SearchPageCacheTagsTest.php @@ -70,6 +70,7 @@ function testSearchText() { $this->assertCacheTag('node:1'); $this->assertCacheTag('user:2'); $this->assertCacheTag('rendered'); + $this->assertCacheTag('http_response'); $this->assertCacheTag('node_list'); // Updating a node should invalidate the search plugin's index cache tag. @@ -83,6 +84,7 @@ function testSearchText() { $this->assertCacheTag('node:1'); $this->assertCacheTag('user:2'); $this->assertCacheTag('rendered'); + $this->assertCacheTag('http_response'); $this->assertCacheTag('node_list'); // Deleting a node should invalidate the search plugin's index cache tag. @@ -172,6 +174,7 @@ public function testSearchTagsBubbling() { 'config:search.page.node_search', 'search_index', 'search_index:node_search', + 'http_response', 'rendered', 'node_list', ]; diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index 9ecefad..d0751bd 100644 --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -343,7 +343,7 @@ public function testReferencedEntity() { // 'user.permissions' is a required cache context, and responses that vary // by this cache context when requested by anonymous users automatically // also get this cache tag, to ensure correct invalidation. - $page_cache_tags = Cache::mergeTags(['rendered'], ['config:user.role.anonymous']); + $page_cache_tags = Cache::mergeTags(['http_response', 'rendered'], ['config:user.role.anonymous']); // If the block module is used, the Block page display variant is used, // which adds the block config entity type's list cache tags. $page_cache_tags = Cache::mergeTags($page_cache_tags, \Drupal::moduleHandler()->moduleExists('block') ? ['config:block_list'] : []); @@ -401,6 +401,7 @@ public function testReferencedEntity() { $context_metadata = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts); $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $context_metadata->getCacheTags()); } + debug($referencing_entity_cache_tags); $this->verifyRenderCache($cid, $referencing_entity_cache_tags, $redirected_cid); $this->pass("Test non-referencing entity.", 'Debug'); @@ -641,7 +642,7 @@ public function testReferencedEntity() { // Verify cache hits. $referencing_entity_cache_tags = Cache::mergeTags($this->referencingEntity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags()); - $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, ['rendered']); + $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, ['http_response', 'rendered']); $nonempty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->getAdditionalCacheTagsForEntityListing()); $nonempty_entity_listing_cache_tags = Cache::mergeTags($nonempty_entity_listing_cache_tags, $page_cache_tags); diff --git a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php index f6da0a2..10c5031 100644 --- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php @@ -53,7 +53,7 @@ public function testEntityUri() { } $expected_cache_tags = Cache::mergeTags($cache_tag, $view_cache_tag); $expected_cache_tags = Cache::mergeTags($expected_cache_tags, $this->getAdditionalCacheTagsForEntity($this->entity)); - $expected_cache_tags = Cache::mergeTags($expected_cache_tags, array($render_cache_tag)); + $expected_cache_tags = Cache::mergeTags($expected_cache_tags, array('http_response', $render_cache_tag)); $this->verifyRenderCache($cid, $expected_cache_tags, $redirected_cid); } diff --git a/core/modules/system/src/Tests/Routing/RouterTest.php b/core/modules/system/src/Tests/Routing/RouterTest.php index 49300c0..202762b 100644 --- a/core/modules/system/src/Tests/Routing/RouterTest.php +++ b/core/modules/system/src/Tests/Routing/RouterTest.php @@ -45,7 +45,7 @@ public function testFinishResponseSubscriber() { // Check expected headers from FinishResponseSubscriber. $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $expected_cache_contexts)); - $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous rendered http_response'); + $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous http_response rendered'); // Confirm that the page wrapping is being added, so we're not getting a // raw body returned. $this->assertRaw('', 'Page markup was found.'); @@ -60,12 +60,12 @@ public function testFinishResponseSubscriber() { $this->drupalGet('router_test/test18'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url']))); - $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered http_response'); + $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo http_response rendered'); // 2. controller result: render array, per-role cacheable route access. $this->drupalGet('router_test/test19'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles']))); - $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered http_response'); + $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo http_response rendered'); // 3. controller result: Response object, globally cacheable route access. $this->drupalGet('router_test/test1'); $headers = $this->drupalGetHeaders(); @@ -79,13 +79,13 @@ public function testFinishResponseSubscriber() { // 5. controller result: CacheableResponse object, globally cacheable route access. $this->drupalGet('router_test/test21'); $headers = $this->drupalGetHeaders(); - $this->assertEqual($headers['x-drupal-cache-contexts'], ''); - $this->assertEqual($headers['x-drupal-cache-tags'], ''); + $this->assertEqual($headers['x-drupal-cache-contexts'], 'http_response'); + $this->assertEqual($headers['x-drupal-cache-tags'], 'http_response'); // 6. controller result: CacheableResponse object, per-role cacheable route access. $this->drupalGet('router_test/test22'); $headers = $this->drupalGetHeaders(); $this->assertEqual($headers['x-drupal-cache-contexts'], 'user.roles'); - $this->assertEqual($headers['x-drupal-cache-tags'], ''); + $this->assertEqual($headers['x-drupal-cache-tags'], 'http_response'); // Finally, verify that the X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags // headers are not sent when their container parameter is set to FALSE. diff --git a/core/modules/views/src/Tests/GlossaryTest.php b/core/modules/views/src/Tests/GlossaryTest.php index 508a4eb..2a5bc90 100644 --- a/core/modules/views/src/Tests/GlossaryTest.php +++ b/core/modules/views/src/Tests/GlossaryTest.php @@ -95,6 +95,7 @@ public function testGlossaryView() { 'node_list', 'user:0', 'user_list', + 'http_response', 'rendered', // FinishResponseSubscriber adds this cache tag to responses that have the // 'user.permissions' cache context for anonymous users.