Commit bfe59b21 authored by catch's avatar catch
Browse files

Issue #2922570 by Berdir, paulocs, anmolgoyal74, dww, ravi.shankar, tobiasb,...

Issue #2922570 by Berdir, paulocs, anmolgoyal74, dww, ravi.shankar, tobiasb, catch, plach, longwave, dawehner, joseph.olstad, alexpott, larowlan, Spokje, andypost, aamouri, Wim Leers, Daniel Kulbe, shabana.navas, klasseng, dschenk, ducktape, marcoliver, anevins, SaschaHannes, pankaj.singh, rpsu, tanubansal, Dom.: The node view page triggers a lot of expensive access checks for relationship links
parent af924ba2
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -101,6 +101,32 @@ public function view(EntityInterface $_entity, $view_mode = 'full') {
    $page['#entity_type'] = $_entity->getEntityTypeId();
    $page['#' . $page['#entity_type']] = $_entity;

    // Add canonical and shortlink links if the entity has a canonical
    // link template and is not new.
    if ($_entity->hasLinkTemplate('canonical') && !$_entity->isNew()) {

      $url = $_entity->toUrl('canonical')->setAbsolute(TRUE);
      $page['#attached']['html_head_link'][] = [
        [
          'rel' => 'canonical',
          'href' => $url->toString(),
        ],
        TRUE,
      ];

      // Set the non-aliased canonical path as a default shortlink.
      $page['#attached']['html_head_link'][] = [
        [
          'rel' => 'shortlink',
          'href' => $url->setOption('alias', TRUE)->toString(),
        ],
        TRUE,
      ];

      // Since this generates absolute URLs, it can only be cached "per site".
      $page['#cache']['contexts'][] = 'url.site';
    }

    return $page;
  }

+12 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
use Drupal\comment\Entity\Comment;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
@@ -158,4 +159,15 @@ protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) {
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function getDefaultCacheContexts() {
    return [
      'languages:' . LanguageInterface::TYPE_INTERFACE,
      'theme',
      'user.permissions',
    ];
  }

}
+11 −0
Original line number Diff line number Diff line
@@ -14,6 +14,17 @@ class ContentTestTranslationUITest extends ContentTranslationUITestBase {
   */
  protected $testHTMLEscapeForAllLanguages = TRUE;

  /**
   * {@inheritdoc}
   */
  protected $defaultCacheContexts = [
    'languages:language_interface',
    'theme',
    'url.query_args:_wrapper_format',
    'user.permissions',
    'url.site',
  ];

  /**
   * Modules to enable.
   *
+1 −45
Original line number Diff line number Diff line
@@ -63,51 +63,7 @@ public static function create(ContainerInterface $container) {
   * {@inheritdoc}
   */
  public function view(EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
    $build = parent::view($node, $view_mode, $langcode);

    foreach ($node->uriRelationships() as $rel) {
      $url = $node->toUrl($rel)->setAbsolute(TRUE);
      // Add link relationships if the user is authenticated or if the anonymous
      // user has access. Access checking must be done for anonymous users to
      // avoid traffic to inaccessible pages from web crawlers. For
      // authenticated users, showing the links in HTML head does not impact
      // user experience or security, since the routes are access checked when
      // visited and only visible via view source. This prevents doing
      // potentially expensive and hard to cache access checks on every request.
      // This means that the page will vary by user.permissions. We also rely on
      // the access checking fallback to ensure the correct cacheability
      // metadata if we have to check access.
      if ($this->currentUser->isAuthenticated() || $url->access($this->currentUser)) {
        // Set the node path as the canonical URL to prevent duplicate content.
        $build['#attached']['html_head_link'][] = [
          [
            'rel' => $rel,
            'href' => $url->toString(),
          ],
          TRUE,
        ];
      }

      if ($rel == 'canonical') {
        // Set the non-aliased canonical path as a default shortlink.
        $build['#attached']['html_head_link'][] = [
          [
            'rel' => 'shortlink',
            'href' => $url->setOption('alias', TRUE)->toString(),
          ],
          TRUE,
        ];
      }
    }

    // Since this generates absolute URLs, it can only be cached "per site".
    $build['#cache']['contexts'][] = 'url.site';

    // Given this varies by $this->currentUser->isAuthenticated(), add a cache
    // context based on the anonymous role.
    $build['#cache']['contexts'][] = 'user.roles:anonymous';

    return $build;
    return parent::view($node, $view_mode);
  }

  /**
+2 −2
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ public function testRecentNodeBlock() {
    $this->assertSession()->pageTextContains($node3->label());
    $this->assertSession()->pageTextContains($node4->label());

    $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']);
    $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.site', 'user']);

    // Enable the "Powered by Drupal" block only on article nodes.
    $edit = [
@@ -165,7 +165,7 @@ public function testRecentNodeBlock() {
    $label = $block->label();
    // Check that block is not displayed on the front page.
    $this->assertNoText($label);
    $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route']);
    $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
Loading