Issue #2973356 by mxr576, kristiaanvandeneynde, wim leers, berdir, bbrala: Cacheability information from route access checker access results are ignored by dynamic_page_cache
parent
6df676adb2
commit
f77f2caa75
|
@ -40,8 +40,13 @@ class RouteAccessResponseSubscriber implements EventSubscriberInterface {
|
|||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
$access_result = $request->attributes->get(AccessAwareRouterInterface::ACCESS_RESULT);
|
||||
$response->addCacheableDependency($access_result);
|
||||
// It is possible that route access checking did not occur, for example,
|
||||
// when an exception was thrown during route matching. This could happen in
|
||||
// an implementation of \Drupal\Core\Routing\EnhancerInterface.
|
||||
// @see \Drupal\jsonapi\Revisions\ResourceVersionRouteEnhancer::enhance()
|
||||
if ($request->attributes->has(AccessAwareRouterInterface::ACCESS_RESULT)) {
|
||||
$response->addCacheableDependency($request->attributes->get(AccessAwareRouterInterface::ACCESS_RESULT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Drupal\Tests\announcements_feed\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
|
||||
|
||||
|
@ -26,6 +25,7 @@ final class AnnouncementsCacheTest extends BrowserTestBase {
|
|||
protected static $modules = [
|
||||
'announcements_feed',
|
||||
'dynamic_page_cache',
|
||||
'node',
|
||||
'toolbar',
|
||||
];
|
||||
|
||||
|
@ -33,14 +33,16 @@ final class AnnouncementsCacheTest extends BrowserTestBase {
|
|||
* Tests dynamic page cache.
|
||||
*/
|
||||
public function testDynamicPageCache(): void {
|
||||
$node_type = $this->drupalCreateContentType();
|
||||
$node = $this->drupalCreateNode(['type' => $node_type->id()]);
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'access toolbar',
|
||||
'access announcements',
|
||||
]));
|
||||
// Front-page is visited right after login.
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'MISS');
|
||||
// Reload the page, it should be cached now.
|
||||
$this->drupalGet(Url::fromRoute('<front>'));
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->elementExists('css', '[data-drupal-announce-trigger]');
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
|
||||
}
|
||||
|
|
|
@ -276,8 +276,15 @@ class DynamicPageCacheSubscriber implements EventSubscriberInterface {
|
|||
// that is a no-op when Dynamic Page Cache runs; priority 25).
|
||||
$events[KernelEvents::REQUEST][] = ['onRequest', 27];
|
||||
|
||||
// Run before HtmlResponseSubscriber::onRespond(), which has priority 0.
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 100];
|
||||
// Run before:
|
||||
// * HtmlResponseSubscriber::onRespond(), which has priority 0.
|
||||
// * AnonymousUserResponseSubscriber::onRespond(). which has priority 5,
|
||||
// and it bubbles up cacheability information for anonymous users.
|
||||
// Run after:
|
||||
// * RouteAccessResponseSubscriber::onRespond() which has priority 10, and
|
||||
// it adds cacheability information from the access result returned by
|
||||
// the route access checker.
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 7];
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
|
|
@ -73,3 +73,10 @@ dynamic_page_cache_test.html.uncacheable.tags:
|
|||
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::htmlUncacheableTags'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
|
||||
dynamic_page_cache_test.html.uncacheable.route_access:
|
||||
path: '/dynamic-page-cache-test/html/uncacheable/route-access'
|
||||
defaults:
|
||||
_controller: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::cacheableResponse'
|
||||
requirements:
|
||||
_custom_access: '\Drupal\dynamic_page_cache_test\DynamicPageCacheTestController::uncacheableAccessCheck'
|
||||
|
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Drupal\dynamic_page_cache_test;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Access\AccessResultInterface;
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
|
@ -139,4 +141,14 @@ class DynamicPageCacheTestController {
|
|||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an uncacheable access result.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function uncacheableAccessCheck(): AccessResultInterface {
|
||||
return AccessResult::allowed()->addCacheContexts(['user']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -123,6 +123,11 @@ class DynamicPageCacheIntegrationTest extends BrowserTestBase {
|
|||
// Cache.
|
||||
$this->drupalGet('dynamic-page-cache-test/html/uncacheable/tags');
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'MISS');
|
||||
|
||||
// Route access checkers can also bubble up cacheability data.
|
||||
$this->drupalGet('/dynamic-page-cache-test/html/uncacheable/route-access');
|
||||
$this->assertSession()->responseHeaderExists(DynamicPageCacheSubscriber::HEADER);
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'UNCACHEABLE');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
|||
* @see \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
|
||||
*/
|
||||
public static function getSubscribedEvents(): array {
|
||||
// Run before the dynamic page cache subscriber (priority 100), so that
|
||||
// Run before the dynamic page cache subscriber (priority 7), so that
|
||||
// Dynamic Page Cache can cache flattened responses.
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 128];
|
||||
return $events;
|
||||
|
|
|
@ -287,7 +287,7 @@ class FileUploadTest extends ResourceTestBase {
|
|||
// This request fails despite the upload succeeding, because we're not
|
||||
// allowed to view the entity we're uploading to.
|
||||
$response = $this->fileRequest($uri, $this->testFileData);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $uri, $response, FALSE, ['4xx-response', 'http_response'], ['url.query_args', 'url.site', 'user.permissions']);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $uri, $response, FALSE, ['4xx-response', 'http_response'], ['url.query_args', 'url.site', 'user.permissions'], FALSE, 'UNCACHEABLE');
|
||||
|
||||
$this->setUpAuthorization('GET');
|
||||
|
||||
|
|
|
@ -3230,7 +3230,8 @@ abstract class ResourceTestBase extends BrowserTestBase {
|
|||
$expected_cacheability = $expected_response->getCacheableMetadata();
|
||||
// Only add node type check tags for non-default revisions.
|
||||
$expected_cache_tags = !in_array($relationship_type, $default_revision_types, TRUE) ? Cache::mergeTags($expected_cacheability->getCacheTags(), $this->getExtraRevisionCacheTags()) : $expected_cacheability->getCacheTags();
|
||||
$this->assertResourceResponse(200, $expected_document, $actual_response, $expected_cache_tags, $expected_cacheability->getCacheContexts(), FALSE, 'MISS');
|
||||
$dynamic_cache = !empty(array_intersect(['user', 'session'], $expected_cacheability->getCacheContexts())) ? 'UNCACHEABLE' : 'MISS';
|
||||
$this->assertResourceResponse(200, $expected_document, $actual_response, $expected_cache_tags, $expected_cacheability->getCacheContexts(), FALSE, $dynamic_cache);
|
||||
// Request the related route.
|
||||
$actual_response = $this->request('GET', $related_url, $request_options);
|
||||
$expected_response = $this->getExpectedRelatedResponse('field_jsonapi_test_entity_ref', $request_options, $revision);
|
||||
|
|
|
@ -171,10 +171,13 @@ class NodeBlockFunctionalTest extends NodeTestBase {
|
|||
$this->assertSession()->pageTextNotContains($label);
|
||||
$this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.site', 'user', 'route']);
|
||||
|
||||
// Ensure that a page that does not have a node context can still be cached,
|
||||
// the front page is the user page which is already cached from the login
|
||||
// request above.
|
||||
// Ensure that a page that does not have a node context can still be cached.
|
||||
\Drupal::service('module_installer')->install(['dynamic_page_cache_test']);
|
||||
$this->drupalGet(Url::fromRoute('dynamic_page_cache_test.cacheable_response'));
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Dynamic-Cache', 'MISS');
|
||||
$this->drupalGet(Url::fromRoute('dynamic_page_cache_test.cacheable_response'));
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Dynamic-Cache', 'HIT');
|
||||
\Drupal::service('module_installer')->uninstall(['dynamic_page_cache_test']);
|
||||
|
||||
$this->drupalGet('node/add/article');
|
||||
// Check that block is displayed on the add article page.
|
||||
|
|
|
@ -201,7 +201,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
|||
*/
|
||||
public static function getSubscribedEvents(): array {
|
||||
// Run before \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
|
||||
// (priority 100), so that Dynamic Page Cache can cache flattened responses.
|
||||
// (priority 7), so that Dynamic Page Cache can cache flattened responses.
|
||||
$events[KernelEvents::RESPONSE][] = ['onResponse', 128];
|
||||
return $events;
|
||||
}
|
||||
|
|
|
@ -501,7 +501,8 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
|||
$response = $this->request('GET', $url, $request_options);
|
||||
if ($has_canonical_url) {
|
||||
$this->assertSame(403, $response->getStatusCode());
|
||||
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Dynamic-Cache'));
|
||||
$dynamic_cache = str_starts_with($response->getHeader('X-Drupal-Cache-Max-Age')[0], '0') || !empty(array_intersect(['user', 'session'], explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]))) ? 'UNCACHEABLE' : 'MISS';
|
||||
$this->assertSame([$dynamic_cache], $response->getHeader('X-Drupal-Dynamic-Cache'));
|
||||
}
|
||||
else {
|
||||
$this->assertSame(406, $response->getStatusCode());
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Drupal\Tests\workspaces\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
@ -25,6 +24,7 @@ class WorkspaceSwitcherTest extends BrowserTestBase {
|
|||
protected static $modules = [
|
||||
'block',
|
||||
'dynamic_page_cache',
|
||||
'node',
|
||||
'toolbar',
|
||||
'workspaces',
|
||||
];
|
||||
|
@ -104,14 +104,16 @@ class WorkspaceSwitcherTest extends BrowserTestBase {
|
|||
* Tests that the toolbar workspace switcher doesn't disable the page cache.
|
||||
*/
|
||||
public function testToolbarSwitcherDynamicPageCache(): void {
|
||||
$node_type = $this->drupalCreateContentType();
|
||||
$node = $this->drupalCreateNode(['type' => $node_type->id()]);
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'access toolbar',
|
||||
'view any workspace',
|
||||
]));
|
||||
// Front-page is visited right after login.
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'MISS');
|
||||
// Reload the page, it should be cached now.
|
||||
$this->drupalGet(Url::fromRoute('<front>'));
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->elementExists('css', '.workspaces-toolbar-tab');
|
||||
$this->assertSession()->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
|
||||
}
|
||||
|
|
|
@ -233,15 +233,16 @@ class StandardPerformanceTest extends PerformanceTestBase {
|
|||
'SELECT "data".* FROM "users_field_data" "data" WHERE "data"."uid" IN (2) ORDER BY "data"."uid" ASC',
|
||||
'SELECT "t".* FROM "user__roles" "t" WHERE ("entity_id" IN (2)) AND ("deleted" = 0) AND ("langcode" IN ("en", "und", "zxx")) ORDER BY "delta" ASC',
|
||||
'SELECT "t".* FROM "user__user_picture" "t" WHERE ("entity_id" IN (2)) AND ("deleted" = 0) AND ("langcode" IN ("en", "und", "zxx")) ORDER BY "delta" ASC',
|
||||
'SELECT "name", "value" FROM "key_value" WHERE "name" IN ( "theme:stark" ) AND "collection" = "config.entity.key_store.block"',
|
||||
];
|
||||
$recorded_queries = $performance_data->getQueries();
|
||||
$this->assertSame($expected_queries, $recorded_queries);
|
||||
$this->assertSame(16, $performance_data->getQueryCount());
|
||||
$this->assertSame(60, $performance_data->getCacheGetCount());
|
||||
$this->assertSame(17, $performance_data->getQueryCount());
|
||||
$this->assertSame(86, $performance_data->getCacheGetCount());
|
||||
$this->assertSame(1, $performance_data->getCacheSetCount());
|
||||
$this->assertSame(1, $performance_data->getCacheDeleteCount());
|
||||
$this->assertSame(1, $performance_data->getCacheTagChecksumCount());
|
||||
$this->assertSame(23, $performance_data->getCacheTagIsValidCount());
|
||||
$this->assertSame(37, $performance_data->getCacheTagIsValidCount());
|
||||
$this->assertSame(0, $performance_data->getCacheTagInvalidationCount());
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue