-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] Call Response->setPrivate() instead of sending raw header() when session is started #25583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
b1e8926
to
a87adea
Compare
I think it's more important to be correct on the http boundary than correct internally. |
a87adea
to
23724a2
Compare
I don't quite understand. To me the concept of the
Can you elaborate on that? |
d2c9f7a
to
9f41594
Compare
Failing tests do not seem to be related. |
@@ -60,7 +60,7 @@ class NativeSessionStorage implements SessionStorageInterface | |||
* ("auto_start", is not supported as it tells PHP to start a session before | |||
* PHP starts to execute user-land code. Setting during runtime has no effect). | |||
* | |||
* cache_limiter, "" (use "0" to prevent headers from being sent entirely). | |||
* cache_limiter, "0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, maybe you have something with this PR :)
I wouldn't change this: the default should be safe when this storage is used without the SaveSessionListener.
instead, I would suggest to change this setting at the same place where SaveSessionListener is registered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a different opinion I have to admit :-) To me, Symfony‘s biggest strength has always been the abstraction of Request and Response. Saving the session doesn‘t work automatically, it‘s dependent of the SaveSessionListener. Just the same as making it private should be. I would even go further and check if the session is actually empty and if so, unset the session cookie. That, in my opinion, would be the real clean way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the thing you're missing is that the session subsystem doesn't know about Request/Response objects, despite being in the same component.
the thing that does the link is SaveSessionListener
which means NativeSessionStorage should have a safe default when used without Req/Resp objects (ie send "private" itself as does native php)
Then when both Session and Req/Resp are used, then SaveSessionListener does the link, and then also the cache_limiter should be set to "0".
I would even go further and check if the session is actually empty and if so, unset the session cookie
isn't that already the case since #24523? or do you mean something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to add that I think I have the same opinion as yours. I'm just trying to help finding a way to make that happen with the current code, without breaking everything :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand your point. We could merge the header onto the response object if present but we don't know if it was set by the session handler or not so that doesn't sound like a very safe idea to me.
isn't that already the case since #24523? or do you mean something else?
Yeah you're right, I missed that sorry :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the patch I mean. Looks enough to me, isn't it?
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 6f972ce..73f612d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -825,7 +825,7 @@ class FrameworkExtension extends Extension
// session storage
$container->setAlias('session.storage', $config['storage_id'])->setPrivate(true);
- $options = array();
+ $options = array('cache_limiter' => '0');
foreach (array('name', 'cookie_lifetime', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'use_cookies', 'gc_maxlifetime', 'gc_probability', 'gc_divisor', 'use_strict_mode') as $key) {
if (isset($config[$key])) {
$options[$key] = $config[$key];
diff --git a/src/Symfony/Component/HttpKernel/EventListener/SaveSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/SaveSessionListener.php
index 36809b5..7a733bd 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/SaveSessionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/SaveSessionListener.php
@@ -53,6 +53,7 @@ class SaveSessionListener implements EventSubscriberInterface
$session = $event->getRequest()->getSession();
if ($session && $session->isStarted()) {
$session->save();
+ $event->getResponse()->setPrivate();
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, that could work out 😄 I'm off for 2 weeks now with no internet so feel free to adjust what's needed if you feel like it cannot wait. Will work on it when I'm back if it can :) Merry X-mas @nicolas-grekas, thanks for all the hard work you put into Symfony 🎉
9f41594
to
44d8510
Compare
…r() when session is started
44d8510
to
dbc1c1c
Compare
Thank you @Toflar. |
…g raw header() when session is started (Toflar) This PR was merged into the 3.4 branch. Discussion ---------- [HttpKernel] Call Response->setPrivate() instead of sending raw header() when session is started | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #24988 | License | MIT | Doc PR | - As described in #24988 I think the current handling of the `Cache-Control` header set by the `NativeSessionStorage` causes inconsistent behaviour. In #24988 @nicolas-grekas states that if you start a session a response should be considered to be private. I do agree with this but up until now, nobody takes care of this on `kernel.response`. I think we must always suppress the `NativeSessionStorage` from generating any headers by default. Otherwise the `Cache-Control` header never makes it to the `Response` instance and is thus missed by `kernel.response` listeners and for example the Symfony HttpCache. So depending on whether you use Symfony's HttpCache or Varnish as a reverse proxy, caching would be handled differently. Varnish would consider the response to be private if you set the php.ini setting `session.cache_limiter` to `nocache` (which is default) because it will receive the header. HttpCache would not because the `Cache-Control` header is not present on the `Response`. That's inconsistent and may cause confusion or problems when switching proxies. Commits ------- dbc1c1c [HttpKernel] Call Response->setPrivate() instead of sending raw header() when session is started
[edit: strike from me (@nicolas-grekas)] |
Good catch, I totally missed that. |
…tting response "private" (nicolas-grekas) This PR was merged into the 3.4 branch. Discussion ---------- [HttpKernel] Fix session handling: decouple "save" from setting response "private" | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Fixes #25583 (comment) from @Tobion, and provides extra laziness for the "session" service, related to symfony/recipes#333. (deps=high failure will be fixed by merging to upper branches.) Commits ------- f8727b8 [HttpKernel] Fix session handling: decouple "save" from setting response "private"
…tting response "private" (nicolas-grekas) This PR was merged into the 3.4 branch. Discussion ---------- [HttpKernel] Fix session handling: decouple "save" from setting response "private" | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Fixes symfony/symfony#25583 (comment) from @Tobion, and provides extra laziness for the "session" service, related to symfony/recipes#333. (deps=high failure will be fixed by merging to upper branches.) Commits ------- f8727b8 [HttpKernel] Fix session handling: decouple "save" from setting response "private"
…tting response "private" (nicolas-grekas) This PR was merged into the 3.4 branch. Discussion ---------- [HttpKernel] Fix session handling: decouple "save" from setting response "private" | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Fixes symfony/symfony#25583 (comment) from @Tobion, and provides extra laziness for the "session" service, related to symfony/recipes#333. (deps=high failure will be fixed by merging to upper branches.) Commits ------- f8727b8827 [HttpKernel] Fix session handling: decouple "save" from setting response "private"
…rivate automatically (Toflar) This PR was squashed before being merged into the 4.1-dev branch (closes #26681). Discussion ---------- Allow to easily ask Symfony not to set a response to private automatically | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | This PR is related to the many discussions going on about the latest (Symfony 3.4+) changes regarding the way Symfony handles the session. I think we're almost there now, Symfony 4.1 automatically turns responses into `private` responses once the session is started and it's all done in the `AbstractSessionListener` where the session is also saved. In other issues/PRs (symfony/symfony#25583, symfony/symfony#25699, symfony/symfony#24988) it was agreed that setting the response to `private` if the session is started is a good default for Symfony. It was also agreed that setting it to `private` does not always make sense because you **can share a response** across sessions, it just requires a more complex caching setup with shared user context etc. So there must be an easy way to disable this behaviour. Right now it's very hard to do so because what you end up doing is basically decorating the `session_listener` which is very hard because you have to keep track on that over different Symfony versions as the base listener might get additional features etc. The [FOSCacheBundle](FriendsOfSymfony/FOSHttpCacheBundle#438) is already having this problem, [Contao](contao/core-bundle#1388) has the same issue and there will be probably more. Basically everyone that wants to share a response cache across the session will have to decorate the default listener. That's just too hard, so I came up with this solution. The header is easy. Every project can add that easily. It does not require any extension, configuration or adjustment of any service. It's clean, transparent and has absolutely no impact on "default" Symfony setups. Would be happy to have some feedback before 4.1 freeze. Commits ------- 0f36710 Allow to easily ask Symfony not to set a response to private automatically
…rivate automatically (Toflar) This PR was squashed before being merged into the 4.1-dev branch (closes #26681). Discussion ---------- Allow to easily ask Symfony not to set a response to private automatically | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | This PR is related to the many discussions going on about the latest (Symfony 3.4+) changes regarding the way Symfony handles the session. I think we're almost there now, Symfony 4.1 automatically turns responses into `private` responses once the session is started and it's all done in the `AbstractSessionListener` where the session is also saved. In other issues/PRs (#25583, #25699, #24988) it was agreed that setting the response to `private` if the session is started is a good default for Symfony. It was also agreed that setting it to `private` does not always make sense because you **can share a response** across sessions, it just requires a more complex caching setup with shared user context etc. So there must be an easy way to disable this behaviour. Right now it's very hard to do so because what you end up doing is basically decorating the `session_listener` which is very hard because you have to keep track on that over different Symfony versions as the base listener might get additional features etc. The [FOSCacheBundle](FriendsOfSymfony/FOSHttpCacheBundle#438) is already having this problem, [Contao](contao/core-bundle#1388) has the same issue and there will be probably more. Basically everyone that wants to share a response cache across the session will have to decorate the default listener. That's just too hard, so I came up with this solution. The header is easy. Every project can add that easily. It does not require any extension, configuration or adjustment of any service. It's clean, transparent and has absolutely no impact on "default" Symfony setups. Would be happy to have some feedback before 4.1 freeze. Commits ------- 0f36710 Allow to easily ask Symfony not to set a response to private automatically
As described in #24988 I think the current handling of the
Cache-Control
header set by theNativeSessionStorage
causes inconsistent behaviour.In #24988 @nicolas-grekas states that if you start a session a response should be considered to be private. I do agree with this but up until now, nobody takes care of this on
kernel.response
.I think we must always suppress the
NativeSessionStorage
from generating any headers by default. Otherwise theCache-Control
header never makes it to theResponse
instance and is thus missed bykernel.response
listeners and for example the Symfony HttpCache. So depending on whether you use Symfony's HttpCache or Varnish as a reverse proxy, caching would be handled differently. Varnish would consider the response to be private if you set the php.ini settingsession.cache_limiter
tonocache
(which is default) because it will receive the header. HttpCache would not because theCache-Control
header is not present on theResponse
. That's inconsistent and may cause confusion or problems when switching proxies.