Objective

  1. #2205295: Objectify session handler converted Drupal's internal session handling functions into a PHP 5.4 SessionHandler class.

  2. The remainder of session.inc are high-level, public API functions to manage user sessions.

Proposed resolution

  1. Convert the procedural session management functions into a new SessionManager service.

    Note: The functionality of this service/class is named SessionStorage in Symfony (which is a complete misnomer).

  2. Properly inject the session_manager dependency into other services:

    • Cookie authentication provider
    • Cron
  3. Remove /core/includes/session.inc.

API changes

The session management functions in /core/includes/session.inc have been converted into a SessionManager class, which is made available as session_manager service now.

Drupal 7

// Force-start a session.
drupal_session_start();
// Check whether a session has been started.
drupal_session_started();
// Migrate the current session from anonymous to authenticated (or vice-versa).
drupal_session_regenerate();
// Delete the session(s) of a particular user.
drupal_session_destroy_uid($uid);

Drupal 8

$session_manager = \Drupal::service('session_manager');

// Force-start a session.
$session_manager->start();
// Check whether a session has been started.
$session_manager->isStarted();
// Migrate the current session from anonymous to authenticated (or vice-versa).
$session_manager->regenerate();
// Delete the session(s) of a particular user.
$session_manager->delete($uid);
CommentFileSizeAuthor
#85 session.manage.85.patch49.59 KBsun
#81 session.manage.txt12.12 KBsun
#80 session.manage.80.patch49.59 KBsun
#78 interdiff.txt855 bytessun
#78 session.manage.78.patch55.6 KBsun
#75 interdiff.txt1.61 KBsun
#75 session.manage.75.patch48.75 KBsun
#73 interdiff.txt437 bytessun
#73 session.manage.73.patch48.01 KBsun
#71 interdiff.txt659 bytessun
#71 session.manage.71.patch48.01 KBsun
#69 session.manage.69.patch47.96 KBsun
#64 rebase-59-native-session-storage.diff.txt7.78 KBznerol
#60 interdiff.txt9.14 KBsun
#60 session.manage.60.patch47.96 KBsun
#59 interdiff.txt4.82 KBsun
#59 session.manage.58.patch44.68 KBsun
#49 interdiff.txt3.77 KBsun
#49 session.manage.49.patch44.57 KBsun
#47 interdiff.txt4.77 KBsun
#47 session.manage.47.patch44.55 KBsun
#43 interdiff.txt5.78 KBsun
#43 session.manage.43.patch43.46 KBsun
#40 session.manage.txt11.88 KBsun
#40 interdiff.txt23.47 KBsun
#40 session.manage.40.patch40.22 KBsun
#38 session.manage.30.patch18.98 KBParisLiakos
#33 interdiff.txt15.75 KBskipyT
#33 session.manage.33.patch33.88 KBskipyT
#32 interdiff.txt2.09 KBznerol
#32 session.manage.30.patch19.17 KBznerol
#24 interdiff.txt3.43 KBsun
#24 session.manage.24.patch18.97 KBsun
#23 session.manage.21.patch18.76 KBsun
#21 interdiff.txt3 KBsun
#21 session.manage.21.patch18.76 KBsun
#20 interdiff.txt425 bytessun
#20 session.manage.20.patch18.8 KBsun
#17 interdiff.txt843 bytessun
#17 session.manage.17.patch18.8 KBsun
#15 session.manage.txt10 KBsun
#15 interdiff.txt10.41 KBsun
#15 session.manage.15.patch18.8 KBsun
#11 interdiff.txt934 bytesznerol
#11 2228341-convert-session-management-to-service-10.diff16.86 KBznerol
#6 2228341-convert-session-management-to-service-5.diff16.85 KBznerol
#1 2228341-convert-session-management-to-service.diff16.31 KBznerol

Comments

znerol’s picture

sun’s picture

Title: Extract remaining session management functions into a service based on NativeSessionStorage » Objectify public-facing session management functions + remove session.inc
Parent issue: » #1858196: [meta] Leverage Symfony Session components
Related issues: +#2205295: Objectify session handler

NativeSessionStorage comes with tons of own special behavior and presents a significant change to our session handling.

As discussed in IRC, I'd really really prefer to limit this issue to a second baby step:

Just simply objectify the remainder of session.inc + get rid of session.inc.

That's a large enough task of its own. Similarly hairy as #2205295: Objectify session handler, because we need to resolve some Simpletest problems. I'd like to avoid any additional cause for potential problems and change in behavior within this step.

ParisLiakos’s picture

i agree. we should bring the symfony code in over at #1858196: [meta] Leverage Symfony Session components. Then we can have a clearer picture on whats going wrong with testbot and less places to debug.

Lets not remove session.inc here though. Just keep the procedural wrappers and just deprecate them?

sun’s picture

@ParisLiakos: To my knowledge, there are only a handful of calls to those functions throughout core, so converting them should be a no-brainer. That said, we can happily defer that decision to "later" in this issue + keep the procedural wrappers for now — let's focus on the real meat first :-)

znerol’s picture

Status: Active » Needs review

Removed the base class for the moment. Tried some tests and at least session and authorization is passing locally. However, at the end of the batch process I'm logged out (when testing with the UI). @sun, perhaps you have a clue whats going on. Logout seems to happen during batch processing.

Regarding NativeSessionStorage, please take a closer look at the source. The class is really not that big and half of it is just setters and getters. Also I'd like to point out that we need something like the AttributesBag in order to decouple session management from user authentication. IMHO the Symfony session implementation is quite lean and I do not see too much things which may get in the way (except for simpletest).

znerol’s picture

The last submitted patch, 1: 2228341-convert-session-management-to-service.diff, failed testing.

Status: Needs review » Needs work

The last submitted patch, 6: 2228341-convert-session-management-to-service-5.diff, failed testing.

ParisLiakos’s picture

Imo we should:

  1. Create a session service
  2. Make the Cookie authentication provider instead of requiring session.inc, have the session service injected.
  3. Call $this->session->init() instead of drupal_session_initialize().
  4. On cleanup call $this->session->save() instead of drupal_session_commit()

And in general
Stop loading session.inc
Move session.inc's public functions to public methods in session service

This way, we move the session handling to DIC -> win!

sun’s picture

  1. +++ b/core/core.services.yml
    @@ -718,6 +718,12 @@ services:
    +  session.storage:
    +    class: Drupal\Core\Session\Storage
    +    calls:
    +      - [initialize]
    
    +++ b/core/includes/session.inc
    @@ -14,43 +14,7 @@
     function drupal_session_initialize() {
    ...
    +  Drupal::service('session.storage')->initialize();
    
    @@ -59,19 +23,8 @@ function drupal_session_initialize() {
     function drupal_session_start() {
    ...
    +  Drupal::service('session.storage');
    

    I don't get why both drupal_session_initialize() + _start() are calling ::initialize()...?

    The former should not call ::initialize(), 'cos that's part of the DI construction already (very debatable).

    And the latter should call ::start(), because we're *explicitly* asked to start a session, not just initialize it.

  2. +++ b/core/includes/session.inc
    @@ -80,47 +33,14 @@ function drupal_session_start() {
    +function drupal_session_started() {
    +  return Drupal::service('session.storage')->isStarted();
    

    Due to the DI service declaration, checking whether a session was started means that a session WILL BE started - no good ;)

znerol’s picture

1. Fixed

2. The only invocation in head is in the cookie-provider, the problem does not exist there. I left the function in because it is in the symfony interface.

znerol’s picture

Status: Needs work » Needs review
ParisLiakos’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 11: 2228341-convert-session-management-to-service-10.diff, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new18.8 KB
new10.41 KB
new10 KB

Somehow, I can't see why this shouldn't work as-is, without any further adjustments...?

  1. Removed call to initialize() from service definition.
  2. Inject a proper database connection.
  3. Relocate isStarted() for diff consistency with HEAD.
  4. Renamed service to 'session'.
  5. Include drupal_save_session() + fully sync-up old procedural code with new OO code.

For 100% completeness, I'm additionally attaching a diff between 8.x session.inc + Storage.php, generated via:

git diff -b 8.x:core/includes/session.inc core/lib/Drupal/Core/Session/Storage.php > session.manage.txt

Status: Needs review » Needs work

The last submitted patch, 15: session.manage.15.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new18.8 KB
new843 bytes

Fixed invalid PHP syntax.

ParisLiakos’s picture

  1. +++ b/core/core.services.yml
    @@ -718,6 +718,11 @@ services:
    +    class: Drupal\Core\Session\Storage
    
    +++ b/core/lib/Drupal/Core/Session/Storage.php
    @@ -0,0 +1,282 @@
    +class Storage {
    

    we should name it Session too:)

  2. +++ b/core/lib/Drupal/Core/Session/Storage.php
    @@ -0,0 +1,282 @@
    +    $is_https = \Drupal::request()->isSecure();
    +    $cookies = \Drupal::request()->cookies;
    

    we should inject the request

  3. +++ b/core/lib/Drupal/Core/Session/Storage.php
    @@ -0,0 +1,282 @@
    +  public function regenerate() {
    

    Can we name this migrate() instead to emulate Symfony\Component\HttpFoundation\Session\SessionInterface::migrate()? Makes transition easier

Status: Needs review » Needs work

The last submitted patch, 17: session.manage.17.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new18.8 KB
new425 bytes

Fixed invalid method name. Sorry.

sun’s picture

StatusFileSize
new18.76 KB
new3 KB

Addressing 1+3 of #18.

  1. Renamed Storage into Session.
  2. Renamed regenerate() to migrate().

re 2) I can only assume that constructor-injecting the request will open a huge can of worms... the usual lack-of-synchronization drama, if you will.

Status: Needs review » Needs work

The last submitted patch, 21: session.manage.21.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new18.76 KB

Sorry, I missed to rename the actual class in #21... Attached patch adjusts that patch in-place.

sun’s picture

StatusFileSize
new18.97 KB
new3.43 KB

Constructor-inject the request into Session service.

I'm fairly sure this will break, so we probably want to skip that step here...

The last submitted patch, 23: session.manage.21.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 24: session.manage.24.patch, failed testing.

The last submitted patch, 20: session.manage.20.patch, failed testing.

ParisLiakos’s picture

+++ b/core/includes/session.inc
@@ -80,47 +27,14 @@ function drupal_session_start() {
-function drupal_session_started($set = NULL) {
-  static $session_started = FALSE;
-  if (isset($set)) {
-    $session_started = $set;
-  }
-  return $session_started && session_status() === \PHP_SESSION_ACTIVE;
+function drupal_session_started() {
+  return \Drupal::service('session')->isStarted();

so now the $set is ignored if something passes it :)
we need to have the functionality in the Session class changing the started property

jibran’s picture

+++ b/core/lib/Drupal/Core/Session/Session.php
@@ -0,0 +1,292 @@
+class Session {

This is a service we need an interface.

skipyT’s picture

StatusFileSize
new18.98 KB
new846 bytes

fixed the failed tests. now I will do the remaining tasks:
- create an interface for the Session class
- remove session.inc
- class the service from the auth provider and the other files (this will be a little bit harder)
- pushing a new patch in about one hour

skipyT’s picture

Status: Needs work » Needs review
znerol’s picture

StatusFileSize
new19.17 KB
new2.09 KB

I was able to reproduce the test failures in #24. Let's try to track the number of calls to disable and enable and only allow saving the session when static::$disableLevel == 0.

skipyT’s picture

StatusFileSize
new33.88 KB
new15.75 KB

removed session.inc
rewrote every file to use the session service

TODO:
- rename the session service
- create the interface

znerol’s picture

I am very unhappy with the renaming from #15. The session service in symfony is something completely different than the thing we are building here. When we keep the name that way, this will be utterly confusing for everyone. I suggest setting up our services in a similar way like others do. For the reference, this is the session service configuration of the framework bundle: session.xml.

Therefore I suggest the following:

session
[...]\HttpFoundation\Session\Session (the symfony session, implements SessionInterface)
session.storage
Drupal\Core\Session\DefaultStorage or alternatively SessionManager (the stuff from this patch, implements [...]\HttpFoundation\Session\Storage\SessionStorageInterface)
session.handler
Drupal\Core\Session\SessionHandler (the database/mongodb/whatever backend, see also #2228393: Decouple session from cookie based user authentication implements \SessionHandlerInterface and in an ideal world also Drupal\Core\Session\SslAwarySessionHandlerInterface)
skipyT’s picture

Ok, I agree with this renaming strategy. And I think now, when we'll add the interfaces we should already rename those classes in the proper way.

The last submitted patch, 32: session.manage.30.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 33: session.manage.33.patch, failed testing.

ParisLiakos’s picture

Status: Needs work » Needs review
StatusFileSize
new18.98 KB

i am just reuploading the patch in #30 to see if its green.

i am not gonna fight more over naming

sun’s picture

Assigned: Unassigned » sun
Status: Needs review » Needs work

On it.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new40.22 KB
new23.47 KB
new11.88 KB

Attached patch is based on @skipyT's #30 + #33.

(btw, it was a bit hard to figure out what exactly happened around ~#30 and which interdiffs to apply to my local branch...)

  1. Updated remaining calls to drupal_session_regenerate().
  2. Updated all references to "drupal_session_".
  3. Relocate endUserSession() and rename to delete() for diff + clarity purposes.
  4. Make ::initialize() return $this to allow for chained method calls.
  5. Fixed Drupal\system\Tests\Session\SessionTest.
  6. Renamed 'session' service to 'session_manager' (and Session class to SessionManager).
  7. Renamed local variables from $session to $session_manager for clarity.
  8. Properly inject SessionManager dependency into SessionHandler.

For completeness, I'm also attaching a new diff between 8.x session.inc vs. SessionManager again.


@jibran:

This patch will not introduce an interface for SessionManager, because this is just the second baby step, and subsequent follow-up issues will significantly change the session subsystem. Therefore, it does not make sense to introduce an interface (API), because the public API is going to be changed.

Status: Needs review » Needs work

The last submitted patch, 40: session.manage.40.patch, failed testing.

znerol’s picture

Properly inject SessionManager dependency into SessionHandler.

This feels somewhat strange. Can we do it the other way around? I.e. inject the SessionHandler into the SessionManager and let the latter forward enable/disable?

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new43.46 KB
new5.78 KB
  1. Inject SessionManager into Cookie auth provider.
  2. Inject SessionManager into Cron service.
  3. Fixed phpDoc of SessionManager::__construct().

re: #42:

Let's simply stick to the current reality. It doesn't help us to "hide" or ignore dependencies in this conversion.

Much rather the opposite: By injecting them properly, the result is a very clear big picture of how the current classes are inter-operating with each other.

In turn, that allows us to make very simple + clear statements in follow-up issues à la "This class should not get that class injected, because ..."

skipyT’s picture

this look good for me, if we get green on the last patch we can ask for RTBC. I think this will be enough for this step.

ParisLiakos’s picture

Issue tags: +API change

i agree with #44
BUT

If we are removing session.inc and we dont add an interface, what do we write in the change notice? (I dont think we will ever get an api change approval this way)
Thats why we should add an interface. The public facing methods will all remain anyway.

So lets have a Drupal\Core\Session\SessionInterface with the following methods:

enable()
disable()
initialize()
isEnabled()
isStarted()
migrate()
save()
start()

In the future this interface will extend from the symfony one, but there will be no api change there, because those methods will remain.

znerol’s picture

I'm okay with adding an interface for those methods not covered by [...]\HttpFoundation\Session\Storage\SessionStorageInterface. Also in addition express the intention to migrate to the aforementioned interface by rebasing the SessionManager to [...]\HttpFoundation\Session\Storage\NativeSessionStorage.

sun’s picture

StatusFileSize
new44.55 KB
new4.77 KB

Added SessionManagerInterface.

Not going to express any intentions in code, because there is still way too much discussion and disagreement on those fronts ;-) — The ultimate intentions will be figured out in issues, not code comments.

ParisLiakos’s picture

Issue summary: View changes
sun’s picture

StatusFileSize
new44.57 KB
new3.77 KB

After lots of back and forth in IRC, this SessionManager class is actually the equivalent of the concept that Symfony calls "Session Storage" (yet another ugly misnomer!):

https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Htt...

The migrate() method only exists on the Session class in Symfony, which is a concept that does not exist in Drupal core yet:

https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Htt...

Focus is really hard on "yet" — the ultimate goal of the parent issue is to introduce and use that Symfony Session class (as-is) in Drupal core. But this issue here is just a baby step towards that goal - we're not there yet. But still, SessionManager != Session.

Therefore:

Reverted rename of SessionManager::regenerate().

sun’s picture

Issue summary: View changes

Updated + rewrote issue summary to fully reflect the changes of this baby step.

Will create a draft change notice in a moment.

sun’s picture

Draft change notice: https://drupal.org/node/2228871

sun’s picture

Title: Objectify public-facing session management functions + remove session.inc » Objectify session management functions + remove session.inc

Everyone involved in here thinks that this is RTBC, but no one feels bold enough to promote it. — Anyone else out there?

FWIW, the last cross-branch-file diff from #40 is still applicable — only the migrate() method name was reverted back to regenerate().

This should help reviewers to confirm that the actual meat of the former procedural session.inc functions are not actually changed here.

cosmicdreams’s picture

Status: Needs review » Reviewed & tested by the community

looks good to me. I had hoped that we could have removed more usages of global $user in this effort but agree that could happen in a next step.

The focus of this issue largely what we had attempted to do in #1858196: [meta] Leverage Symfony Session components. Great work!

znerol’s picture

We only possibly can start to remove references to the global $user when we have all session components in place.

dawehner’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Authentication/Provider/Cookie.php
    @@ -18,6 +19,23 @@
    +   * @var \Drupal\Core\Session\SessionManager
    ...
    +   * @param \Drupal\Core\Session\SessionManager $session_manager
    

    We do have an interface so we can also typehint that.

  2. +++ b/core/lib/Drupal/Core/Session/SessionManager.php
    @@ -0,0 +1,300 @@
    +  /**
    +   * The master request of this process.
    +   *
    +   * @var \Symfony\Component\HttpFoundation\Request
    +   */
    +  protected $request;
    

    If we explicit need the master request shouldn't we then use the request stack and ask for the master request? What ensures that the request here is the master one.

  3. +++ b/core/lib/Drupal/Core/Session/SessionManager.php
    @@ -0,0 +1,300 @@
    +  /**
    +   * Whether session management is enabled or temporarily disabled.
    +   *
    +   * PHP session ID, session, and cookie handling happens in the global scope.
    +   * This value has to persist, since a potentially wrong or disallowed session
    +   * would be written otherwise.
    +   *
    +   * @var bool
    +   */
    +  protected static $enabled = TRUE;
    +
    +  /**
    +   * Whether the session has been started.
    +   *
    +   * @var bool
    +   */
    +  protected static $started = FALSE;
    

    I don't see why this properties should be static ... everything interacts with actual instances of the object anyway.

  4. +++ b/core/lib/Drupal/Core/Session/SessionManager.php
    @@ -0,0 +1,300 @@
    +  /**
    +   * Returns whether the current PHP process runs on CLI.
    +   *
    +   * Command line clients do not support cookies nor sessions.
    +   *
    +   * @return bool
    +   */
    +  protected function isCli() {
    +    return PHP_SAPI === 'cli';
    +  }
    

    Will we have a better place for drupal_is_cli() in the future?

klausi’s picture

We should also look at SessionTestSubscriber (used in SessionTest.php) where we have to call the ugly "\Drupal::currentUser()->getAccount();" just to initialize the session. That should probably be replaced with some start() call to the session manager service.

znerol’s picture

Assigned: sun » znerol

I don't see why this properties should be static ... everything interacts with actual instances of the object anyway.

Simpletest woes. Probably needs better documentation.

I also discovered that it is actually a requirement that we implement SessionStorageInterface in order to be able to use the new session manager together with the Symfony Session object. Therefore I'd like to explore now whether it would be revisit the original proposal and make SessionManager a subclass of NativeSessionStorage. With the interface being almost identical, i expect changes to be minimal.

sun’s picture

Assigned: znerol » sun
Status: Needs work » Needs review
StatusFileSize
new44.68 KB
new4.82 KB

Thanks for your reviews!

Please note that this issue intentionally is a second baby step only. We are purposively NOT changing any implementations and/or calling code. The existing functionality is converted as-is into a service only.

  1. Type-hint SessionManagerInterface instead of SessionManager.
  2. Fixed phpDoc for $request properties.

re: #56.3: Both $enabled and $started were static variables previously, so this is taken over literally from HEAD. It is required for tests to pass, in particular because web tests as well as the installer are futzing with these global/static session state properties. The code is moved as-is. Figuring out a more appropriate home for these properties and methods is out of scope of this issue. That will be part of the later steps in the transition to Symfony's session handling.

re: #56.4: drupal_is_cli() is only inlined into the SessionManager class to remove an unnecessary dependency on procedural code. This method is not supposed to be a replacement for drupal_is_cli() (is is protected to begin with).


re: #57: If that is required in HEAD, then it is also required with this patch, because the implementation is not changed at all. This patch converts the remainder of session.inc into a service/class.

As transparently demonstrated with the cross-branch-file diff session.manage.txt in #40, the class contains the exact same code. No functional changes.

Our one and only intention here are the steps outlined in the issue summary. We want to avoid scope-creep at all costs, because that is what caused #1858196: [meta] Leverage Symfony Session components to get stuck forever.

The vast majority of this code will most likely be relocated and significantly changed, once we have the baseline to get back to work on the conversion to Symfony's session handling.

sun’s picture

StatusFileSize
new47.96 KB
new9.14 KB
  1. Inject RequestStack instead of current Request into SessionManager.
  2. Inject RequestStack instead of Request into SessionHandler.

2) is for consistency; I hope that it doesn't break anything.

Status: Needs review » Needs work

The last submitted patch, 60: session.manage.60.patch, failed testing.

dawehner’s picture

For now using the current request is exactly what core does. We should think about using the master request explicit in a follow up.

sun’s picture

Status: Needs work » Postponed
znerol’s picture

StatusFileSize
new7.78 KB

I still think that it would be very worthwile to rebase SessionManager onto NativeSessionStorage. The changes really are trivial. Attached is not a full patch but an interdiff of the proposed changes (applies to #59). @sun pretty please can we get them in here?

znerol’s picture

Ignore #64. Regrettably this is still flawed, definitely needs more thought.

sun’s picture

60: session.manage.60.patch queued for re-testing.

sun’s picture

Status: Postponed » Needs review

Status: Needs review » Needs work

The last submitted patch, 60: session.manage.60.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new47.96 KB

Merged 8.x.

Status: Needs review » Needs work

The last submitted patch, 69: session.manage.69.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new48.01 KB
new659 bytes

Added CLI check to SessionManager::initialize() to account for Drush.

Status: Needs review » Needs work

The last submitted patch, 71: session.manage.71.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new48.01 KB
new437 bytes

D'oh. It certainly helps to comply with the interface ;-)

Status: Needs review » Needs work

The last submitted patch, 73: session.manage.73.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new48.75 KB
new1.61 KB

The test failures all happen to be related to Locale. Debugging those yields the following backtrace:

Fatal error: Call to a member function isSecure() on a non-object
  in \core\lib\Drupal\Core\Session\SessionManager.php on line 85

drupal_handle_request( )	..\index.php:15
drupal_bootstrap( )	..\bootstrap.inc:1461
_drupal_bootstrap_code( )	..\bootstrap.inc:1408
file_get_stream_wrappers( )	..\common.inc:2926
Drupal\Core\Extension\ModuleHandler->invokeAll( )	..\file.inc:211
call_user_func_array ( )	..\ModuleHandler.php:315
locale_stream_wrappers( )	..\ModuleHandler.php:315
t( )	..\locale.module:210
Drupal\Core\StringTranslation\TranslationManager->translate( )	..\bootstrap.inc:1013
Drupal\Core\StringTranslation\TranslationManager->getStringTranslation( )	..\TranslationManager.php:139
Drupal\locale\LocaleTranslation->getStringTranslation( )	..\TranslationManager.php:119
Drupal\locale\LocaleLookup->__construct( )	..\LocaleTranslation.php:110
Drupal\Core\Session\AccountProxy->getRoles( )	..\LocaleLookup.php:99
Drupal\Core\Session\AccountProxy->getAccount( )	..\AccountProxy.php:93
Drupal\Core\Authentication\AuthenticationManager->authenticate( )	..\AccountProxy.php:77
Drupal\Core\Authentication\Provider\Cookie->authenticate( )	..\AuthenticationManager.php:95
Drupal\Core\Session\SessionManager->initialize( )	..\Cookie.php:51

file_get_stream_wrappers() is invoked during bootstrap, before HttpKernel::handle() adds the current request to the request stack.

In #2229223: RequestStack is not persisted across kernel rebuilds, I sorta intentionally skipped drupal_handle_request() + _drupal_boostrap_kernel(), because I (wrongly) assumed that this code path would not be possible...

→ Fixed current request is not available in request stack before HttpKernel::handle().

This effectively duplicates the master request in the request stack, but I do not see a way to work around that without significantly changing how Drupal is bootstrapped.

Status: Needs review » Needs work

The last submitted patch, 75: session.manage.75.patch, failed testing.

znerol’s picture

Instead of injecting request / request_stack into the constructor of SessionManager, how about adding a $request parameter to the initialize method?

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new55.6 KB
new855 bytes

Fixed mock Request in DUTB is not added to request stack.

Status: Needs review » Needs work

The last submitted patch, 78: session.manage.78.patch, failed testing.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new49.59 KB

Oh, sorry. Last patch was bogus. :-/

sun’s picture

StatusFileSize
new12.12 KB

Back green again. :-)

For completeness, I'm attaching a final diff between session.inc and SessionManager, generated via:

git diff -b 8.x:core/includes/session.inc core/lib/Drupal/Core/Session/SessionManager.php > session.manage.txt
cosmicdreams’s picture

Status: Needs review » Reviewed & tested by the community

@znerol shifting to setting injection instead of constructor injection doesn't buy us much.

The patch is green now so Yay! This is a solid step forward

znerol’s picture

shifting to setting injection instead of constructor injection doesn't buy us much.

No injection at all, just pass in the request to initialize from the caller function (which would have been possible and would have solved the problem). But certainly I'm happy that this turned green again without that additional change.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 80: session.manage.80.patch, failed testing.

sun’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new49.59 KB

Merged 8.x. Just a merge conflict in DUTB due to a changed comment.

cosmicdreams’s picture

85: session.manage.85.patch queued for re-testing.

sun’s picture

@cosmicdreams: RTBC patches are automatically re-tested once per day now.

sun’s picture

Moving forward here would allow us to validate some testing framework related changes in the kernelize-bootstrap patch.

cosmicdreams’s picture

@sun Oh good news. No more manual retests.

I'm seeing a lot of issues modify their titles to include the number of issues that are postponed by parent issues. It might make sense to round up all the session related issues that relate to this and see if any need to be postponed until this issue gets in. I'm specifically thinking of how #961508: Dual http/https session cookies interfere with drupal_valid_token() will have a significant reroll because of this issue. There are likely others.

webchick’s picture

Assigned: sun » alexpott
Priority: Normal » Major

This one's a bit over my head, and catch has a busy week, so tossing over to Alex.

Also this "feels" major-ish, since the related issue is as well, although I could be wrong.

cosmicdreams’s picture

While it seems major, it's not doing anything different than it used to. We're just objectifying here.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/core.services.yml
@@ -718,6 +719,11 @@ services:
+  session_manager:
+    class: Drupal\Core\Session\SessionManager
+    arguments: ['@request_stack', '@database']
+    tags:
+      - { name: persist }

Looking at the code in DrupalKernal I just can not see how a persisted service can ever actually be swapped out once the container is compiled. If a module swaps the session_manager then the persist logic will copy the old one back over the top and then the container will be dumped. The only way I can see would be to manually delete the container once the module that alters the session manager is installed.

Can we add a test to show that I'm wrong?

sun’s picture

Status: Needs work » Needs review

@alexpott: I'm not sure how that is related to this issue?

The current persist functionality does not persist service definitions, it only persists instances of services.

Instantiated services are persisted until DrupalKernel is shut down (which resets the entire container to null).

Therefore, if a (new) module swaps out a persisted service, then the new service definition will kick in as soon as DrupalKernel is shut down and rebooted from scratch (typically happening on a new request, but also possible through a manual shutdown()boot() sequence).

Especially because SessionManager registers the SessionHandler to PHP core, that is a required behavior here, since swapping out and registering a new session handler to PHP core mid-request is not something that can reasonably work (without a facility to migrate an existing session from one session handler to a new session handler).

In addition, swapping out session.inc mid-request is and was not possible before in HEAD either, because procedural functions can only be loaded once.

Therefore, this patch only converts the existing functionality and behavior as-is. I know you have reservations regarding persisted services (though possibly also a misunderstanding of how persisted services work?), but that is status quo and the only existing mechanism in HEAD. — We can discuss to replace that mechanism with a better one and/or possible ways to eliminate ModuleHandler::updateModules(), but that's a very complex separate discussion to have and it's not clear why that should hold up this issue...?

alexpott’s picture

Status: Needs review » Reviewed & tested by the community

So @sun is correct - I wrote a module to swap out the container and the dumped version contains the replaced class...

  /**
   * Gets the 'session_manager' service.
   *
   * This service is shared.
   * This method always returns the same instance of the service.
   *
   * @return Drupal\session\AltSessionManager A Drupal\session\AltSessionManager instance.
   */
  protected function getSessionManagerService()
  {
    return $this->services['session_manager'] = new \Drupal\session\AltSessionManager($this->get('request_stack'), $this->get('database'));
  }

Setting back to rtbc as I was responsible for derailing.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 12abe62 and pushed to 8.x. Thanks!

  • Commit 12abe62 on 8.x by alexpott:
    Issue #2228341 by sun, znerol, skipyT, ParisLiakos: Objectify session...
sun’s picture

Assigned: alexpott » sun

Thanks! :-)

znerol’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.