diff --git a/core/modules/big_pipe/big_pipe.module b/core/modules/big_pipe/big_pipe.module index 1970c27d988c8a752990542f330740ee3075b4b1..18bbbb22cda89c9243463cf3fd2fc97c96ef4857 100644 --- a/core/modules/big_pipe/big_pipe.module +++ b/core/modules/big_pipe/big_pipe.module @@ -48,19 +48,32 @@ function big_pipe_page_attachments(array &$page) { // avoid endless redirect loops. $has_big_pipe_nojs_cookie = $request->cookies->has(BigPipeStrategy::NOJS_COOKIE); $page['#cache']['contexts'][] = 'cookies:' . BigPipeStrategy::NOJS_COOKIE; - if ($session_exists && !$has_big_pipe_nojs_cookie) { - $page['#attached']['html_head'][] = [ - [ - // Redirect through a 'Refresh' meta tag if JavaScript is disabled. - '#tag' => 'meta', - '#noscript' => TRUE, - '#attributes' => [ - 'http-equiv' => 'Refresh', - // @todo: Switch to Url::fromRoute() once https://www.drupal.org/node/2589967 is resolved. - 'content' => '0; URL=' . Url::fromUri('internal:/big_pipe/no-js', ['query' => \Drupal::service('redirect.destination')->getAsArray()])->toString(), + if ($session_exists) { + if (!$has_big_pipe_nojs_cookie) { + // Let server set the BigPipe no-JS cookie. + $page['#attached']['html_head'][] = [ + [ + // Redirect through a 'Refresh' meta tag if JavaScript is disabled. + '#tag' => 'meta', + '#noscript' => TRUE, + '#attributes' => [ + 'http-equiv' => 'Refresh', + // @todo: Switch to Url::fromRoute() once https://www.drupal.org/node/2589967 is resolved. + 'content' => '0; URL=' . Url::fromUri('internal:/big_pipe/no-js', ['query' => \Drupal::service('redirect.destination')->getAsArray()])->toString(), + ], ], - ], - 'big_pipe_detect_nojs', - ]; + 'big_pipe_detect_nojs', + ]; + } + else { + // Let client delete the BigPipe no-JS cookie. + $page['#attached']['html_head'][] = [ + [ + '#tag' => 'script', + '#value' => 'document.cookie = "' . BigPipeStrategy::NOJS_COOKIE . '=1; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"', + ], + 'big_pipe_detect_js', + ]; + } } } diff --git a/core/modules/big_pipe/src/Controller/BigPipeController.php b/core/modules/big_pipe/src/Controller/BigPipeController.php index 282a634e623addaecef3cd0dc99a09566d650e8b..1f055e0553d25cff041c96ac1d4689d5aa1947ec 100644 --- a/core/modules/big_pipe/src/Controller/BigPipeController.php +++ b/core/modules/big_pipe/src/Controller/BigPipeController.php @@ -56,7 +56,8 @@ public function setNoJsCookie(Request $request) { } $response = new LocalRedirectResponse($request->query->get('destination')); - $response->headers->setCookie(new Cookie(BigPipeStrategy::NOJS_COOKIE, TRUE)); + // Set cookie without httpOnly, so that JavaScript can delete it. + $response->headers->setCookie(new Cookie(BigPipeStrategy::NOJS_COOKIE, TRUE, 0, '/', NULL, FALSE, FALSE)); $response->addCacheableDependency((new CacheableMetadata())->addCacheContexts(['cookies:' . BigPipeStrategy::NOJS_COOKIE, 'session.exists'])); return $response; } diff --git a/core/modules/big_pipe/src/Tests/BigPipeTest.php b/core/modules/big_pipe/src/Tests/BigPipeTest.php index b30d27b8807b208ea58f73e5f476d7d69c1ef980..65b9f0f50176e958bf23a3efedf81cb08e48e04b 100644 --- a/core/modules/big_pipe/src/Tests/BigPipeTest.php +++ b/core/modules/big_pipe/src/Tests/BigPipeTest.php @@ -7,6 +7,7 @@ namespace Drupal\big_pipe\Tests; +use Drupal\big_pipe\Render\Placeholder\BigPipeStrategy; use Drupal\Component\Serialization\Json; use Drupal\Component\Utility\Html; use Drupal\Core\Url; @@ -78,20 +79,25 @@ protected function performMetaRefresh() { * - \Drupal\big_pipe\Controller\BigPipeController */ public function testNoJsDetection() { + $no_js_to_js_markup = '<script>document.cookie = "' . BigPipeStrategy::NOJS_COOKIE . '=1; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"</script>'; + // 1. No session (anonymous). $this->drupalGet(Url::fromRoute('<front>')); $this->assertSessionCookieExists(FALSE); $this->assertBigPipeNoJsCookieExists(FALSE); $this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL='); + $this->assertNoRaw($no_js_to_js_markup); // 2. Session (authenticated). $this->drupalLogin($this->rootUser); $this->assertSessionCookieExists(TRUE); $this->assertBigPipeNoJsCookieExists(FALSE); $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/1" />' . "\n" . '</noscript>'); + $this->assertNoRaw($no_js_to_js_markup); $this->assertBigPipeNoJsMetaRefreshRedirect(); $this->assertBigPipeNoJsCookieExists(TRUE); $this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL='); + $this->assertRaw($no_js_to_js_markup); $this->drupalLogout(); // Close the prior connection and remove the collected state. @@ -105,9 +111,11 @@ public function testNoJsDetection() { $this->assertSessionCookieExists(TRUE); $this->assertBigPipeNoJsCookieExists(FALSE); $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/login" />' . "\n" . '</noscript>'); + $this->assertNoRaw($no_js_to_js_markup); $this->assertBigPipeNoJsMetaRefreshRedirect(); $this->assertBigPipeNoJsCookieExists(TRUE); $this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL='); + $this->assertRaw($no_js_to_js_markup); // Close the prior connection and remove the collected state. $this->curlClose(); @@ -119,11 +127,13 @@ public function testNoJsDetection() { $this->assertSessionCookieExists(FALSE); $this->assertBigPipeNoJsCookieExists(FALSE); $this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL='); + $this->assertNoRaw($no_js_to_js_markup); $this->drupalLogin($this->rootUser); $this->drupalGet(Url::fromRoute('big_pipe_test.no_big_pipe')); $this->assertSessionCookieExists(TRUE); $this->assertBigPipeNoJsCookieExists(FALSE); $this->assertNoRaw('<noscript><meta http-equiv="Refresh" content="0; URL='); + $this->assertNoRaw($no_js_to_js_markup); } /**