Problem/Motivation
If you want to return different responses for the same request, depending on values of HTTP headers, resulting response cannot be cached neither in internal nor in external response-level cache.
Examples of such requests:
- Browser language negotiation (#2430335: Browser language detection is not cache aware) should have different results depending on visitor's language preferences, sent in "Accept-Language" header.
- Site needs to display local sales office to people depending on their originating country. Many CDN providers (Cloudflare, Akamai etc.) sent this information in HTTP header.
The only existing way to return headers-dependent response is to mark it non-cacheable (use KillSwitch policy). That happens because cacheability metadata that contains "header" context (implemented in HeadersCacheContext class) is only stored in renderable arrays, but not exposed to reverse proxies (or internal page context).
Proposed resolution
Introduce new Vary page response policy, that will tell reverse proxies how to properly cache returned responses. This proposal was originally raised in #2430335: Browser language detection is not cache aware, but moved to the new issue, as it solves a bigger problem.
@catch in https://www.drupal.org/project/drupal/issues/2430335#comment-12842970 argues against usage of vary header in core itself, but with all respect, I cannot agree - Vary is the standard HTTP way of informing proxies about cache contexts of the origin server, especially when the response varies depending on one or more HTTP headers. Vary header is here exactly for this purpose, so it seems natural to use it.
Remaining tasks
- Rewrite the patch from https://www.drupal.org/project/drupal/issues/2430335#comment-12840473, leaving only the part that introduces new response policy (and it's test)
- Modify the patch in #2430335: Browser language detection is not cache aware to only contain changes needed for browser language negotiation.
User interface changes
- No UI changes
API changes
- New page_cache_vary service that triggers adding Vary header
Release notes snippet
Issue priority
Major since it unblocks major bug #2430335: Browser language detection is not cache aware
| Comment | File | Size | Author |
|---|---|---|---|
| #31 | interdiff_24-31.txt | 871 bytes | ravi.shankar |
| #31 | 3023104-31.patch | 8.05 KB | ravi.shankar |
| #24 | interdiff_22-24.txt | 979 bytes | vsujeetkumar |
| #24 | 3023104-24.patch | 8.06 KB | vsujeetkumar |
| #22 | interdiff-21_22.txt | 500 bytes | gauravvvv |
Issue fork drupal-3023104
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
valthebaldComment #4
znerol commentedRegrettably this approach clearly violates the
ResponsePolicyInterfacecontract. While not stated explicitly in the documentation, thecheck()method is certainly not expected to actually change the response.Comment #7
vidorado commentedRerolled patch for Drupal core 8.7.6
Comment #9
fago> Site needs to display local sales office to people depending on their originating country. Many CDN providers (Cloudflare, Akamai etc.) sent this information in HTTP header.
Afaik this was the original path during Drupal 8 development, but it was replaced by the current approach of using URLS and the support fro the `_format` query parameters. This was done since there is only bad or hardly proper support for the Vary http headers across proxies and CDNs, so using the query parameters makes the url is different and cachable.
I guess that decision could be re-evaluated now, since a couple of years passed, but that's the status quo.
Comment #10
heddnI think this file made it into the latest patch on accident.
Comment #11
ravi.shankar commentedRerolled patch #7 on Drupal 9.1.x and addressed comment #10.
Comment #13
heddnTagging novice for the minor test fixes for the failures in https://www.drupal.org/pift-ci-job/1850261.
Comment #14
heddnA couple of questions, not necessarily novice their answers.
setVary has a
$replaceflag available to it. Should we expose that on the interface for add? Which leads to the next question, do we need to have an interface for this Vary class, or is that not necessary?There is a hasVary method on the response. We should use it.
Comment #15
Kumar Kundan commentedTest fixes of #11.
Comment #16
heddnComment #18
tanubansal commentedTested #15 on 9.1, 'Vary' page cache response has been added
Comment #20
gung wang commentedDrupal core 9.2.3 and Composer 2.1.5.
I run "composer update" after add the patch into composer.json, but I got an error:
In my composer.json file
Thank you very much!
Comment #21
ranjith_kumar_k_u commentedRe-rolled #15 for 9.3
Comment #22
gauravvvv commentedRe-rolled patch #21, Fixed custom command failed. Added interdiff for same.
Comment #24
vsujeetkumar commentedFixed the fail test, Please have a look.
Comment #25
longwaveQuestions/comments in #14 still not addressed.
Comment #26
znerol commentedAs the author of the
, I'd like to point out that #4 is not addressed neither. This approach is invalid, please try to find a different extension point to solve the issue.
Comment #30
nevergoneContrib blocker, see: #3222748-30: Create a page if given internal path is not valid
Comment #31
ravi.shankar commentedAddressed point #14.2 of comment #14, keeping the status needs work for comment #14.1.
Comment #33
nitesh624Any update on this issue?
Will this be included in core?
Comment #34
bbrala#2430335: Browser language detection is not cache aware has been updated to use a responsesubscriber that allows setting Vary headers. Wonder if those changes also need partial split into this issue?
Comment #35
dpagini commentedFrom #4...
I don't think this is resolved with the current approaches still, as suggested in #26.
I have solved this in my own project with an event subscriber for KernelEvents::RESPONSE. I think that would be a relatively simple change to make here. Would that address the concerns of #4?
Comment #36
dpagini commentedSorry @bbrala - this is nearly the same thing you are suggesting as well... but I do think that issue #2430335 would do most of what this issue is trying to do from what I can see.
Comment #37
elendev commentedAs commented in https://www.drupal.org/project/drupal/issues/2972483, I've developed the module page_cache_vary until the issue is fixed in the core page_cache module.
It can retrieve cache vary headers by caching them per URL, so that the cost of computing the vary headers is as minimal as possible.
If this solution is good enough, I can try to integrate it directly in Drupal, let me know what you think.
Comment #38
bbralaTalked with catch avout a possible angle of attack which would make this viable (possobel) from a variation and perdormance perspective. Will post that sometime soon.
Comment #39
maxilein commentedSee here: https://www.drupal.org/project/drupal/issues/2972483 a module that might help in the meantime: https://www.drupal.org/project/page_cache_vary