Exposed in #2551419: Abstract RenderCache into a separate service that is capable of cache redirects in a non-render array-specific way so you can read the full thought process there but here's the TLDR:
Both X-Drupal-Cache-Tags
and X-Drupal-Cache-Contexts
are set in FinishResponseSubscriber
(FRS). This is before page cache gets the response but after dynamic page cache has handled it. This is wrong for both tags and contexts.
To add insult to injury, FRS folds the cache contexts before setting them in the header, but does not similarly affect the cache tags. This is very misleading for numerous reasons:
- Only the cache contexts gathered up until DynamicPageCacheSubscriber (DPCS) truly matter because that's where they'll affect the cache. Any contexts added later on -such as in RouteAccessResponseSubscriber (RARS)- do nothing at all because page cache doesn't leverage contexts, only tags.
- By folding the contexts in FRS, we therefore expose incorrect data. Suppose we got to DPCS with
user.permissions
and notuser
, but RARS would adduser
to the response, thenX-Drupal-Cache-Contexts
would simply showuser
, even though the DPC stored the page withuser.permissions
- If we are folding contexts, it affects the tags. This is not represented in
X-Drupal-Cache-Tags
The reason this currently works with our thousands of tests checking for the 2 headers is twofold:
- RenderCache (accidentally?) bleeds information about folded contexts/tags, which causes it to bubble up to the response. By rewriting RenderCache in the issue linked at the top, this became very obvious through many test fails.
- Most of our tests check for the wrong contexts because their writers seemingly had no clue how broken the headers were. We even have tests checking for
user
after foldinguser.permissions
, but not the tags set by said folding.
Proposed solution
In the long run, we should move X-Drupal-Cache-Tags
to PageCache, where it actually makes sense. We should also move X-Drupal-Cache-Contexts
to DPCS where it makes sense for contexts to be debugged.
This will, however lead to ambiguity in X-Drupal-Cache-Tags
because we might want to debug tags for DPC and PC individually. So I suggest we add a third header X-Drupal-Dynamic-Cache-Tags
and rename the context one to X-Drupal-Dynamic-Cache-Contexts
.
We can finally add X-Drupal-Cache-Contexts-Deprecated
to PageCache and allow failing tests to check that header while we clean them up on a smaller scale in follow-ups. The end goal would be to remove said header altogether.