8000 [HttpKernel] AbstractSessionListener should not override the cache lifetime for private responses by rodmen · Pull Request #48651 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[HttpKernel] AbstractSessionListener should not override the cache lifetime for private responses #48651

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

Merged
merged 1 commit into from
Dec 15, 2022
Merged

Conversation

rodmen
Copy link
Contributor
@rodmen rodmen commented Dec 14, 2022
Q A
Branch? 5.4
Bug fix? yes
New feature? no
Deprecations? no
Tickets Fix #47660 AbstractSessionListener should not override the cache lifetime
License MIT

#47660 is opened as a bug
This PR fix that AbstractSessionListener override the max-age and the expires cache headers if cache control is private and these values are explicit defined

@carsonbot
Copy link

It looks like you unchecked the "Allow edits from maintainer" box. That is fine, but please note that if you have multiple commits, you'll need to squash your commits into one before this can be merged. Or, you can check the "Allow edits from maintainers" box and the maintainer can squash for you.

Cheers!

Carsonbot

@@ -200,10 +200,14 @@ public function onKernelResponse(ResponseEvent $event)
}

if ($autoCacheControl) {
$maxAge = 0;
if (!$response->headers->hasCacheControlDirective('public') && (bool) $response->getMaxAge()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest this CS instead:

         if ($autoCacheControl) {
+            $maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge();
             $response
-                ->setExpires(new \DateTime())
+                ->setExpires(new \DateTimeImmutable('+'.$maxAge.' seconds'))

But LGTM otherwise thanks!

(please allow edits from maintainers, that makes it easier to deal with contributions on our side)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @nicolas-grekas ,
I have applied the suggested CS, looks better now.
I can't allow edits for maintainers... I think it's because I opened the PR from an organization repository and that option is not available in that case (please correct me if I'm wrong).

@nicolas-grekas
Copy link
Member

Thank you @rodmen.

@nicolas-grekas nicolas-grekas merged commit 7e2a88a into symfony:5.4 Dec 15, 2022
@fabpot fabpot mentioned this pull request Dec 16, 2022
This was referenced Dec 28, 2022
@pkruithof
Copy link
Contributor

I'm not sure whether this is the appropriate place, but I think I found a bug regarding this change (I'll open an actual issue if I'm correct about this).

In our case, we have the following situation:

At least, this is the intention (I think). What actually happens now is this:

  • getMaxAge() calculates the value when not explicitly set by subtracting the response date from the expires date
  • getExpires() can't form a DateTimeImmutable from its -1 value and falls back on a default date in the past
  • this way getMaxAge() eventually does {date in the past} - {current date}, which in my particular case (at this moment) yields -172800
  • new \DateTimeImmutable('+'.$maxAge.' seconds') is now tomorrow:
    php > var_dump((new DateTimeImmutable('+-172800 seconds'))->format('c'));
    string(25) "2023-01-06T15:28:04+00:00"
    # (it's currently Jan. 5th)
    

So now we have a 302 response that has private, no-cache and max-age=0, but with an Expires header in the future. And apparently Firefox treats this as cacheable, so even after logging in, when visiting the original url I still get redirected to the auth provider because it serves the original 302 response from cache.

Sorry for the long description, but do you agree this is a bug? If so I'll file an issue or just a PR right away. I think the intended behaviour should be to only overwrite max-age=0 when the response is public.

8000

@stof
Copy link
Member
stof commented Jan 4, 2023

this indeed looks like a bug

fabpot added a commit that referenced this pull request Feb 4, 2023
…uithof, fabpot)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[Response] `getMaxAge()` returns non-negative integer

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Refs #48651 (comment)
| License       | MIT
| Doc PR        |

The `max-age` directive should be a non-negative integer, see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control):

> The max-age=N request directive indicates that the client allows a stored response that is generated on the origin server within N seconds — where N may be any non-negative integer (including 0).

In case the value is negative, it's encouraged to be treated as 0:

> In other words, for any max-age value that isn't an integer or isn't non-negative, the caching behavior that's encouraged is to treat the value as if it were 0.

In my case, it lead to a response that was `private,no-cache` but with an `Expires` header set in the future. Not every browser handled this inconsistency the same, which eventually led to authentication issues (see linked comment for a more elaborate explanation).

Commits
-------

2639c43 [Response] `getMaxAge()` returns non-negative integer
symfony-splitter pushed a commit to symfony/http-kernel that referenced this pull request Feb 4, 2023
…uithof, fabpot)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[Response] `getMaxAge()` returns non-negative integer

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Refs symfony/symfony#48651 (comment)
| License       | MIT
| Doc PR        |

The `max-age` directive should be a non-negative integer, see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control):

> The max-age=N request directive indicates that the client allows a stored response that is generated on the origin server within N seconds — where N may be any non-negative integer (including 0).

In case the value is negative, it's encouraged to be treated as 0:

> In other words, for any max-age value that isn't an integer or isn't non-negative, the caching behavior that's encouraged is to treat the value as if it were 0.

In my case, it lead to a response that was `private,no-cache` but with an `Expires` header set in the future. Not every browser handled this inconsistency the same, which eventually led to authentication issues (see linked comment for a more elaborate explanation).

Commits
-------

2639c4353a [Response] `getMaxAge()` returns non-negative integer
symfony-splitter pushed a commit to symfony/http-foundation that referenced this pull request Feb 4, 2023
…uithof, fabpot)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[Response] `getMaxAge()` returns non-negative integer

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Refs symfony/symfony#48651 (comment)
| License       | MIT
| Doc PR        |

The `max-age` directive should be a non-negative integer, see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control):

> The max-age=N request directive indicates that the client allows a stored response that is generated on the origin server within N seconds — where N may be any non-negative integer (including 0).

In case the value is negative, it's encouraged to be treated as 0:

> In other words, for any max-age value that isn't an integer or isn't non-negative, the caching behavior that's encouraged is to treat the value as if it were 0.

In my case, it lead to a response that was `private,no-cache` but with an `Expires` header set in the future. Not every browser handled this inconsistency the same, which eventually led to authentication issues (see linked comment for a more elaborate explanation).

Commits
-------

2639c4353a [Response] `getMaxAge()` returns non-negative integer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0