-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Allow to easily ask Symfony not to set a response to private automatically #26681
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
Allow to easily ask Symfony not to set a response to private automatically #26681
Conversation
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.
that would be much more elegant than the hacks we currently have to do. any possibility to get this (or something similar) into 4.1?
eZ Platform would also greatly benefit from this, since it also uses shared response across different sessions with the same user context. |
If you share a response between sessions, you still have an issue with the cookie header containing one of the session ids. How do you handle it in this case ? |
@stof In eZ Platform case, and probably in FOS HTTP Cache bundle, |
->setPrivate() | ||
->setMaxAge(0) | ||
->headers->addCacheControlDirective('must-revalidate'); | ||
if (!$response->headers->has('Symfony-NoPrivateIfSessionStarted')) { |
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.
This would allow cache poisoning if an external request comes with this header, isn't it?
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.
Why would the response contain such a header based on an external request?
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 no sorry, I read it as a "request". What about using a request parameter instead?
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.
This check should also be moved upper in the method.
The name of the parameter should be more accurate, eg session.disable_auto_cache_control
or better?
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 don't think this is correct. The question in that piece of code is
Hello response. I will now make you private if the session is started because that's what's a sane default. However, if someone wanted you to really be public even though the session is started, I'll leave you alone.
The subject is the response, not the request. Normally caching systems would add cache tagging headers to the response, set the cache control headers etc. It's all done on the response, never the request.
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.
This check should also be moved upper in the method.
The name of the parameter should be more accurate, eg session.disable_auto_cache_control or better?
Why upper? Where exactly do you mean? And the parameter can be changed yes but as it's a header I think it should be more in the header naming style, no?
@stof There's a lot more to consider, you are right. This is why Symfony defaults to setting the response |
But any new feature on Symfony would not be applicable to 3rd party bundles, unless they plan to support Symfony 4.1 only. |
I'm sorry but I don't think I understand what you're saying, @nicolas-grekas. |
To illustrate the FOSHttpCache (and afaik ez publish) use case:
Its ok that symfony by default ignores what the application is telling about caching when the session has been used to generate the response. But for special cases like this, we need a way to disable this behaviour. Doing it with a response header seems the best solution because then it can be per response, but without needing a complicated configuration for the symfony listener as to which responses to handle or not. For symfony 4.0, we simply decorate the SessionListener and only call the inner listener it when there is no |
We only register our decorator for symfony 3.4 or newer because before, the caching headers are not overwritten. If we can get such a solution into Symfony 4.1, we can limit the decorator to just 3.4 - 4.0 |
@Toflar @dbu thanks for the details, OK on my side then :)
I mean as early as possible in the method, eg not sure we need to check for the session service at all.
this name is not accurate: max-age and must-revalidate also are removed. |
Naming things, right? π Sounds perfect to me, changed. |
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.
(never mind the comment about the place of the check, I missed the logic in the patched "if")
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 was trying to think of an even better name but did not find any. this seems good enough. but i would make that into a constant, its also better in code using this as the relation would become explicit.
the class doc of the listener should be updated. it lacks mention of anything that is done with the response. i would say something like:
Checks if the session has been started and overrides the Cache-Control header to avoid all caching in that case. If you have a scenario where caching responses with session information in them makes sense, you can disable this behaviour by setting the header SessionListener::SESSION_NO_AUTO_CACHE_CONTROL on the response.
This listener also saves the session if it still open.
->setPrivate() | ||
->setMaxAge(0) | ||
->headers->addCacheControlDirective('must-revalidate'); | ||
if (!$response->headers->has('Symfony-Session-NoAutoCacheControl')) { |
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.
imho this should be a public constant. then the constant can also be documented a little bit to explain what this is about.
I agree but at the same time, I don't want to change a PR that has been approved already. Waiting for mergers to comment on that. BTW: Failing tests are unrelated. |
The const looks good to me. |
Done then, thanks for the feedback! |
* | ||
* @author Johannes M. Schmitt <[email protected]> | ||
* @author Tobias Schultze <http://tobion.de> | ||
*/ | ||
abstract class AbstractSessionListener implements EventSubscriberInterface | ||
{ | ||
const SESSION_NO_AUTO_CACHE_CONTROL = 'Symfony-Session-NoAutoCacheControl'; |
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.
*_HEADER?
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.
and remove SESSION_?
AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER
?
* Sets the session in the request. | ||
* Sets the session onto the request on the "kernel.request" event and saves | ||
* it on the "kernel.response" event. | ||
* In addition, if the session has been started it overrides the Cache-Control |
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.
blank line need before
6540ef3
to
d85ba56
Compare
Done. |
d85ba56
to
0f36710
Compare
Thank you @Toflar. |
β¦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
@Toflar would you mind sending a doc PR to tell about this please? |
Done a while ago π symfony/symfony-docs#9667 |
Oups, sorry, I added the link in the description. |
Ah sorry, yes @javiereguiluz pinged me before the 4.1 release in a separate ticket so I forgot to update this one. Cheers! |
@nicolas-grekas maybe i have missed something, but have you planed to make the same changes in 3.4 version, meaning adding the Symfony-Session-NoAutoCacheControl header to make cache behaviour same as before! If not i need to urgently rollback to previous version! I proposed a PR #27814 ! hope that will do it |
@nicolas-grekas Is this available in the latest 3.4.x, if not is there any plan to make it available? |
That's a new feature of 4.1, and 3.4 is in bug-fixes-only mode. |
Thank you, I will look into upgrading to 4.1, seems like tons of work. In the mean time, would there be an easy way to migrate this to the 3.4 version? I'm thinking of overriding the session_listener for Symfony and use the new code inside. Would that be a good approach? In such case should I run a compiler pass to remove the core session_listener definition then re-define it with my pass to point to my custom class? |
I don't remember where exactly but yes, a listener can do it also. |
Yes, you can decorate the core listener. Can you tell me what exactly you're trying to do? I'm like 99% sure I have a better alternative for you where you don't have to do this at all or at least not on your own π |
@Toflar thank you for your response. My situation is that even with the session already started, I would like to be able to set the cache headers manually. NO_AUTO_CACHE_CONTROL_HEADER is exactly what I needed but I cannot upgrade to 4.1 at this moment (I'm on 3.4 and upgrading requires too much work that we cannot arrange the time at the moment) What I ended up doing was:
It seems to do the trick for now until I upgrade to 4.x version and remove this hack. |
Yeah basically that's what we did for FOSCacheBundle, which would maybe also cover your use-case, which is why I asked what you're trying to do :) |
Thanks @yellow1912 for the compiler pass idea! |
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 theAbstractSessionListener
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 toprivate
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 is already having this problem, Contao 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.