-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] Bugfix/last modified response strategy #42355
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
[HttpKernel] Bugfix/last modified response strategy #42355
Conversation
The failing tests don't seem related to me. |
src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php
Outdated
Show resolved
Hide resolved
I also stumbled over these lines: symfony/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php Lines 177 to 184 in 71db7e7
I can't remember why we added the check for |
I tried to find an answer to my own question. @Toflar pointed out that |
Sorry if I'm not getting this entirely, but the idea of this PR is to allow e.g. a request including ESI to pass the Wouldn't this change break if there's an actual 304 being returned by the app?
I tested this locally and could reproduce that behavior. This could be easily fixed with |
Interesting that you could reproduce this locally, I didn't check on that at all. What I figured out is:
The point of the PR (or what @mpdude) meant in the original issue was to forward the most-recent
|
@aschempp My steps to reproduce this are not that trivial to explain, I hope I can though. ;) Request:
Response:
2b. is where I get a 500 because the response is not considered successful. With this PR and low maxage I can observe one request being fine, one failing each time the cache is fresh enough. |
I think I understand the problem, but rather because we're dealing with subrequests a lot in Contao (we even have our own fragment handler). The However, that's not really part of this PR and should probably be a separate issue? The proposed changes would neither fix nor worsen that. But it would allow the main request (the |
In my testing, depending on cache freshness, there were 500 status responses, caused by this throw: Upstream isn't doing anything wrong – it's allowed to send a 304 as far as I'm aware of – and the app should not be forced to change it's behavior, no matter whether a CacheKernel is being used or not (again, as far as I understand it). The changes in this PR would lead to a 500 response when there was none before. Even worse, serving a newly generated response works and subsequent responses won't, so it might be hard to debug that. In my opinion this is a BC break, because nowhere in the docs there's a warning "Don't ever response with a 304 in fragment sub-requests" and, even though the status code was always 200, it would work as of now. |
But the code lines you mentioned are not added by this pull request? The current surrogate (ESI) implementation do not allow for a response code <> 2xx, therefore this problem should also appear without this pull request? Can you please try to reproduce this in your local setup without my changes? |
Let me try to explain it differently (I hope I can, language barrier is restricting). SetupLet's say there's a Symfony project that has been setting the last-modified header on sub-requests. Have a look at https://github.com/aleho/symfony-httpcache for a demo, it doesn't even set the upstream response to 304, just a last-modified header and 200, including content. ProblemBefore your changes, no response would include a After this PR there will be a It's true that this PR doesn't cause the root problem and the issue currently can also be triggered by setting the request header. Nevertheless, this PR will definitely always trigger it, because clients implementing a cache are expected to request with Solution (just my suggestion)Don't merge this PR unless |
@aschempp Are there any updates on this? (Edit / PS: A made a PR fixing the 304 issue described above.) |
It is a considered a new feature as it introduces something that was explicitly not supported before. Can you rebase on 6.2 so that I can merge (the code looks good to me.) |
@aschempp Are you still interested in this PR? |
…aleho) This PR was merged into the 4.4 branch. Discussion ---------- [HttpKernel] [HttpCache] Don't throw on 304 Not Modified | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fixes #43997 | License | MIT | Doc PR | ~ If the response cache keeps a `Last-Modified` header clients will request with `If-Modified-Since`. The surrogate will not handle a `304 Not Modified` correctly, resulting in a 500 and a failed request. This fixes that request / response cycle, as observed in testing PR #42355. Commits ------- d27f02a [HttpKernel] [HttpCache] Don't throw on 304 Not Modified
71db7e7
to
2f862bb
Compare
PR updated 😊 |
b39c5f1
to
f3aae33
Compare
Thank you @aschempp. |
…ional requests (mpdude) This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [HttpKernel] ESI fragment content may be missing in conditional requests | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | | License | MIT The content for ESI-embedded fragments may be missing from the combined (main) response generated by the `HttpCache` under certain conditions: 1. The main request sent to the cache must be a conditional request with either `If-Modified-Since` or `If-None-Match` 2. The embedded response processed by the cache matches the validator (last-modified or etag) 3. The resulting (combined) response generated by the `HttpCache` does not match the validator Condition 3 is necessary since otherwise the cache returns an empty 304 response. In that case, the issue still exists, but we don't see or care about it and the wrong body is not sent at all. Regarding condition 2, it does not matter where this embedded response comes from. It may be a fresh (cached) response taken from the cache, it may be a stale cache entry that has been revalidated; probably it can even be a non-cacheable response. In practice, the conditional request will always use `If-Modified-Since`: We're dealing with ESI subrequests, and the combined response created by the `HttpCache` does not provide `ETag`s, so a client has nothing to validate against. Only since #42355 (merged in to 6.2) the main response will include a `Last-Modified` header, given that all of the included responses provided one. Probably that is the reason why this bug was not spotted earlier - it required that change and all of the responses processed by the cache must provide `Last-Modified` data. Conditions 2 + 3 together seem unlikely, but may in fact happen easily when you have an application that generates different chunks of cacheable content for the main and embedded requests and adds last-modified information to them. For example: * First request: Main response modified at time 1, embedded fragment modified at time 2 -> last-modified at 2 * Data for main response changes at time 3 * Second request with "If-Modified-Since" time 2 * Embedded fragment still modified at time 2, main response at time 3 -> last-modified at 3 * the embedded fragment is considered as not modified, content is stripped * main response is generated, fragment content is missing Commits ------- 9fed8dc [HttpKernel] ESI fragment content may be missing in conditional requests
…omputation with ESI responses (mpdude) This PR was merged into the 6.4 branch. Discussion ---------- [HttpKernel] Improve and add tests for `Last-Modified` computation with ESI responses | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | | License | MIT This PR slightly improves the test cases for #42355 (which fixed #41666). It adds two tests for the cases where `Last-Modified` should _not_ be added, and updates the existing test to make it more obvious that we only look at the existence of `Last-Modified` headers, whereas the `ETag` is not relevant. Commits ------- 40d5455 Improve and add tests for Last-Modified computation with ESI responses
The
HttpCache
uses theResponseCacheStrategy
to merge caching headers when merging ESI or SSI fragments into the main response content. Caching headers are merged as far as possible (age, cache-control/max-age, etc.). However, we forgot to merge theLast-Modified
header which prevents revalidation of responses.from @mpdude in #41666