diff options
Diffstat (limited to 'core/lib')
-rw-r--r-- | core/lib/Drupal/Core/DrupalKernel.php | 26 | ||||
-rw-r--r-- | core/lib/Drupal/Core/StackMiddleware/Session.php | 31 | ||||
-rw-r--r-- | core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php | 8 |
3 files changed, 57 insertions, 8 deletions
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index dd67a2b5416f..d778693888f6 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -28,6 +28,8 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\TerminableInterface; @@ -582,6 +584,11 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { (bool) Settings::get(RequestSanitizer::SANITIZE_LOG, FALSE) ); + // Ensure that there is a session on every request. + if (!$request->hasSession()) { + $this->initializeEphemeralSession($request); + } + $this->loadLegacyIncludes(); // Load all enabled modules. @@ -1638,4 +1645,23 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { return $config['profile'] ?? NULL; } + /** + * Initializes a session backed by in-memory store and puts it on the request. + * + * A simple in-memory store is sufficient for command line tools and tests. + * Web requests will be processed by the session middleware where the mock + * session is replaced by a session object backed with persistent storage and + * a real session handler. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @see \Drupal\Core\StackMiddleware\Session::handle() + */ + protected function initializeEphemeralSession(Request $request): void { + $session = new Session(new MockArraySessionStorage()); + $session->start(); + $request->setSession($session); + } + } diff --git a/core/lib/Drupal/Core/StackMiddleware/Session.php b/core/lib/Drupal/Core/StackMiddleware/Session.php index d9da60ac6025..94841e1508dd 100644 --- a/core/lib/Drupal/Core/StackMiddleware/Session.php +++ b/core/lib/Drupal/Core/StackMiddleware/Session.php @@ -49,19 +49,42 @@ class Session implements HttpKernelInterface { * {@inheritdoc} */ public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response { + // Initialize and start a session for web requests. Command line tools and + // the parent site in functional tests must continue to use the ephemeral + // session initialized and started in DrupalKernel::preHandle(). if ($type === self::MAIN_REQUEST && PHP_SAPI !== 'cli') { - $session = $this->container->get($this->sessionServiceName); - $session->start(); - $request->setSession($session); + $this->initializePersistentSession($request); } $result = $this->httpKernel->handle($request, $type, $catch); - if ($type === self::MAIN_REQUEST && $request->hasSession()) { + if ($type === self::MAIN_REQUEST && PHP_SAPI !== 'cli' && $request->hasSession()) { $request->getSession()->save(); } return $result; } + /** + * Initializes a session backed by persistent store and puts it on the request. + * + * Sessions for web requests need to be backed by a persistent session store + * and a real session handler (responsible for session cookie management). + * In contrast, a simple in-memory store is sufficient for command line tools + * and tests. Hence, the persistent session should only ever be placed on web + * requests while command line tools and the parent site in functional tests + * must continue to use the ephemeral session initialized in + * DrupalKernel::preHandle(). + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @see \Drupal\Core\DrupalKernel::preHandle() + */ + protected function initializePersistentSession(Request $request): void { + $session = $this->container->get($this->sessionServiceName); + $session->start(); + $request->setSession($session); + } + } diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php index 2e7083ff86f0..737f1ef247e7 100644 --- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php +++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php @@ -23,6 +23,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Yaml\Yaml as SymfonyYaml; use Drupal\Core\Routing\RouteObjectInterface; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\Routing\Route; /** @@ -210,10 +212,6 @@ trait FunctionalTestSetupTrait { protected function rebuildContainer() { // Rebuild the kernel and bring it back to a fully bootstrapped state. $this->container = $this->kernel->rebuildContainer(); - - // Make sure the URL generator has a request object, otherwise calls to - // $this->drupalGet() will fail. - $this->prepareRequestForGenerator(); } /** @@ -254,6 +252,7 @@ trait FunctionalTestSetupTrait { */ protected function prepareRequestForGenerator($clean_urls = TRUE, $override_server_vars = []) { $request = Request::createFromGlobals(); + $request->setSession(new Session(new MockArraySessionStorage())); $base_path = $request->getBasePath(); if ($clean_urls) { $request_path = $base_path ? $base_path . '/user' : 'user'; @@ -265,6 +264,7 @@ trait FunctionalTestSetupTrait { $server = array_merge($request->server->all(), $override_server_vars); $request = Request::create($request_path, 'GET', [], [], [], $server); + $request->setSession(new Session(new MockArraySessionStorage())); // Ensure the request time is REQUEST_TIME to ensure that API calls // in the test use the right timestamp. $request->server->set('REQUEST_TIME', REQUEST_TIME); |