Problem/Motivation
The session save handler currently is hard coded in the session manager constructor. Thus backends wishing to override session storage need to swap out session manager instead of the session save handler.
Note that Symfony also implements a proxy pattern for session handlers. This makes it possible to run code whenever a session is read/written without having to extend the save handler (and thus pollute it with non-storage related functionality). Examples of proxy classes are the WriteCheckSessionHandler which prevents unnecessary writes to the database and also #2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler.
Proposed resolution
- Register the
SessionHandlerassession_handler.storageservice in the container. - Register session handler proxies in the container and tag them with
session_handler_proxy - Implement a compiler pass similar to
StackedKernelPasswhich collects the tagged proxies and wraps them aroundsession_handler.storage. The compiler pass also points the aliassession_handlerto the service at the bottom of this stack.
Remaining tasks
User interface changes
API changes
| Comment | File | Size | Author |
|---|---|---|---|
| #34 | 2372389-session-handler-stack-34.patch | 16.91 KB | almaudoh |
| #28 | 372389-session-handler-stack-28.diff | 16.88 KB | znerol |
| #28 | interdiff.txt | 5.06 KB | znerol |
| #25 | interdiff.txt | 2.46 KB | almaudoh |
| #25 | 2372389-session-handler-stack-25.patch | 13.9 KB | almaudoh |
Comments
Comment #1
znerol commentedComment #2
znerol commentedAdding tests.
Comment #3
znerol commentedFix code-style in test, remove spurious
@paramannotation.Comment #4
znerol commentedComment #5
jhedstrom+1 this looks great. Nice tests and everything.
Comment #6
dawehnerAs talked yesterday, we should document/justify why its okay to create a pass for just a single session service by default.
It would be great to expose the session_handler somehow at least by default in the core.services.yml file, so tools like PHPStorm can do its autocompletion based upon it. Can't you point to some class by default?
+1 to no longer create the session handler automatically
nitpick ... its not a decorated kernel.
Comment #7
znerol commentedReroll. #6 still outstanding.
Comment #8
znerol commentedFixes nitpicks from #6 (2,4).
Re #6.3: In fact it is not optimal to pass in
NULLto the parent constructor, because then it simply instantiates its own session save handler. However, I was forced here to setter-injection because of the circular dependency between the session save handler and the session manager. Now that mixed mode ssl is gone, the only reason why this exists is the enabling/disabling session writes. As per #2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler this should be moved into a session handler proxy anyway, therefore it might be reasonable to just do that in this issue.Comment #9
znerol commentedThis time with attachments.
Comment #10
znerol commentedPostponing this on #2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler.
Comment #11
almaudoh commented#2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler just went in.
Comment #14
almaudoh commentedStraight re-roll
Comment #16
almaudoh commentedFixed test fail due to class members' rename.
Comment #17
znerol commentedNitpick: There are spurious spaces before the closing bracket.
@almaudoh: Thank you very much for driving the session issues forward.
Comment #18
almaudoh commented@znerol: No sweat. You did all the hard work :)
The sessionManager variable is no longer used after #2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler
Comment #19
almaudoh commentedFixes #17 and #18 and adds the
WriteSafeSessionHandleras a session handler proxy service.Comment #20
cpj commentedQuestion about the tests - not sure if this is necessary, but does this simulate a stack with more than one member ?
Comment #21
almaudoh commented@cpj: the test simulates a two member stack and verifies that the higher priority member is called before the lower priority one, as designed.
Comment #22
cpj commented@almaudoh - thanks. I've reviewed and tested the code as far as I can, meaning it runs in our development environment, which is Beta-6 plus other relevant recent patches, and I've stepped through it in the debugger for a simple, non-multi-level stack. I couldn't get HEAD to run yesterday, but I that didn't appear to be related to this patch. Is that sufficient for RTBC ?
Comment #23
cpj commentedComment #24
alexpottGiven that the plan is to not have the write safe handler in the session manger how about extracting the write safe handler in the setSaveHandler method? That way we have less constructor change.
Comment #25
almaudoh commentedAddressed #24
Comment #26
almaudoh commentedNot sure if this is the best way, or whether to allow the exception if null is passed in.
This option caters for the case where another session proxy (higher priority) is added by some other module.
Comment #27
cpj commentedI like the idea to use the setter method for the handler rather than passing it in via the constructor. But I don't understand the need for the hard-coded fall back. Why would the presence of a higher priority session proxy trigger the setter to be called with null ?
Comment #28
znerol commentedI took another look at the issue. First off, the reason why this was postponed on #2338727: Replace static SessionManager::$enabled property with WriteSafeSessionHandler class and resolve hidden circular dependency between SessionManager and SessionHandler was the cyclic dependency. Before the other issue went in, it was only possible to inject the session handler into the session manager via setter-injection. However, the base class of the session manager (Symfonys NativeSessionStorage) will instantiate and register its own session handler if we do not pass anything to its constructor. Even though it would be replaced immediately by the
setSaveHandler()call, that behavior is not desirable at all.Therefore we really want to inject the session handler into the constructor of the session manager. I do not have any preference regarding the write-safe handler, thus going with #24 (i.e. setter injection) for that.
Note that I've added deprecations to
SessionManagerInterfaceisEnabled(),enable()anddisable()methods. Calls to those methods should be replaced by the respective methods of the write-safe handler. A quick grep through the source tree turned up the following files which need to be updated:Comment #29
almaudoh commented@cpj: sorry I wasn't very clear in my earlier comment. A higher priority session proxy handler would mean the setter is called not with null, but an object that doesn't implement
WriteSafeSessionHandlerInterfacehence thesetSessionWritable()method call would fail.The fallback would allow us to still disable session writes since the higher priority proxy may still write through the write-safe handler.
But as has already been stated, this would only be temporary since the writeSafeHandler will be removed from
SessionManagerin a later refactoring.Comment #30
almaudoh commentedRaised follow-up #2426031: Remove deprecated uses of SessionManager::isEnabled(), SessionManager::enable() and SessionManager::disable() to remove deprecated methods. We need someone to RTBC #28 so we can meet the next beta-release window. Anyone??
Comment #31
cpj commentedI tested #19 pretty thoroughly in #22. Reviewing the interdiffs for #25 and #28, I understand the changes to remove then add back the session injection, so as far as I can see #28 is very similar to #19, right ? Therefore I'm gonna set this as RTBC. OK ?
Comment #32
cpj commentedComment #34
almaudoh commentedStraightforward re-roll after #2229145: Register symfony session components in the DIC and inject the session service into the request object got in. Back to RTBC per #32.
Comment #35
alexpottThis issue is a major task that is part of on-going efforts to reduce fragility and improve extensibility of the session system by using Symfony's session components. Per https://www.drupal.org/core/beta-changes, this is a good change to complete during the Drupal 8 beta phase. Committed a32a88c and pushed to 8.0.x. Thanks!
Comment #37
almaudoh commentedThanks @alexpott. Now on to #2426031: Remove deprecated uses of SessionManager::isEnabled(), SessionManager::enable() and SessionManager::disable() which will remove the deprecated uses of
SessionManager::enable(),::disable(), etc.