Problem/Motivation
After #2579847: /node/add is lacking cacheability metadata, causes problems when cached by Dynamic Page Cache and "Use admin theme when editing or creating content" is turned off I have no choice but to file this as a critical. Despite all warnings, we went ahead with default block cache and smart cache. We can not release Drupal 8 like this because everything will break in really mysterious ways.
Proposed resolution
As per dawehner in #2579847-33: /node/add is lacking cacheability metadata, causes problems when cached by Dynamic Page Cache and "Use admin theme when editing or creating content" is turned off require #cache on every controller which returns a render array.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#58 | interdiff.txt | 4.95 KB | dawehner |
#58 | 2579941-58.patch | 26.49 KB | dawehner |
#55 | interdiff.txt | 8.59 KB | dawehner |
#55 | 2579941-55.patch | 22.17 KB | dawehner |
#49 | 2579941-48.patch | 14.3 KB | Wim Leers |
Comments
Comment #2
chx CreditAttribution: chx commentedComment #3
dawehnerLet's see how many fails we have
Comment #4
Wim Leers#2 will come back at least mostly green. It's in the wrong place.
Comment #5
chx CreditAttribution: chx commentedWim's patch fails at node/add (expected after the parent critical) so here's the two rolled together to see how many we have after node/add is fixed.
Comment #6
Wim LeersI think it's a great idea to nudge/force people to think about cacheability, always.
OTOH, this approach means that even on
_admin_route: TRUE
routes,no_cache: TRUE
routes and POST requests, where Dynamic Page Cache doesn't do anything, you'll still be forced to add cacheability metadata. Personally, I think that's great, but that means we'll be forcing people to think about cacheability metadata even in cases where it doesn't make sense to do caching.Comment #7
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedDo we allow to return an empty array?
I assume yes, just asking.
Comment #8
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commented#6:
Can we check the $request->data('smart_cache_cacheable') attribute, e.g. the request policies?
Comment #11
Wim LeersThis moves the exception to Dynamic Page Cache, so it is only thrown when Dynamic Page Cache actually may cache the response. This means all admin routes and
no_cache
routes will work as expected again.(The do-not-test patch is the actual patch, the other one includes #2579847: /node/add is lacking cacheability metadata, causes problems when cached by Dynamic Page Cache and "Use admin theme when editing or creating content" is turned off, just like #5.)
Comment #12
moshe weitzman CreditAttribution: moshe weitzman at Acquia commentedLooks good. Lets have the exception also link to the relevant handbook or API page.
Comment #16
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedOverall I am +1 to making this explicit; however some caveats:
We decided in the smart cache / dynamic_page_cache policy issue that we wanted to make this enabled by default for everything for now and just fix critical core fails with a simple no_cache: TRUE.
It is quite astonishing that we only found one real critical problem so far - which is also a real edge case as that should have been marked no_cache: TRUE already since a while if there were not this strange dynamic adding of admin_route.
So lets not get into a panic situation, where all the world is blowing up. We knew there would be some criticals following from smart cache / dynamic_page_cache and we knew we could simply mark the routes as uncacheable and be done.
I think throwing an Exception is a good developer tool, however it also means a HUGE BC break as a developer now will have to decide:
- opt-in to smart-cache
- opt-out of smart-cache
explicitly.
It means that whoever is returning a render array will either opt-in to dynamic_page_cache or opt-out of dynamic_page_cache or needs to disable dynamic_page_cache locally.
So the previous version of not doing anything is no longer allowed and maybe that is a good thing.
Berdir told me anecdotically that they have not yet enabled smart_cache for the existing production sites, which limits the BC break for existing sites to contrib authors.
I like the idea of checking for #cache, it is what I would have originally wanted to see happen - but did not know how.
To the patch itself:
#11: The event view subscriber should mainly set a flag on the request that the render array was not having '#cache', then the check should be done in smart cache itself after the real response policy check.
The fake response policy check will not work and again lead to false positives.
Comment #17
Wim LeersPer #2556889: [policy, no patch] Decide if SmartCache is still in scope for 8.0 and whether remaining risks require additional mitigation:
This issue is then about
no_cache: TRUE
to all routes in core that aren't yet providing correct cacheability metadata; core can gradually add the necessary cacheability metadata to those routes over time, so that by e.g. Drupal 8.1.0 or 8.2.0, all of the core routes that can be cached, also are, and provide the necessary cacheability metadata.Working on doing point 2. Some of the test controllers that are super trivial to fix, I will just fix.
Comment #18
Wim LeersHeh, I cross-posted with Fabianx. Similar thoughts.
Without that, we will still end up complaining on
_admin_route: TRUE
andno_cache: TRUE
routes, because those are in response policies. Yes, we should actually have "route policies" too, besides just request & response policies.Comment #19
Wim LeersHere's a first (small) round. It's getting late here, and it's been a long day. I will continue in the morning.
Comment #20
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commented#18: Yes, but what I mean is change the code to do:
Just here do:
Then when actually having passed the Response and Request policies in DPC onResponse listener do:
Just when we are about to cache the response we can decide properly on the data that the controller provided no cacheability metadata.
Comment #21
catchNo exception please. trigger_error() should do.
Comment #22
chx CreditAttribution: chx commentedActually isn't this what asserts are made for? Smells like one, isn't it?
Edit:
Comment #24
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedI am fine with assert() or trigger_error() also makes the BC break less.
Comment #25
Wim Leers@catch Which should it be:
trigger_error()
orassert()
? I'll leave the choice to you.This updates the 4XX controller's render arrays. This should also significantly reduce the number of failures.
Comment #28
Wim LeersImplemented #20, which is indeed much better.
Comment #29
dawehnerAh this is much better
Comment #30
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedJust some nits:
I think adding the ->has() check is better / cleaner as a controller can just return a CacheableResponse and then this is NULL.
We also use ->has() for some other attributes - in the rest of the code.
Comment #32
Wim LeersLet's provide more useful information to developers. And let's add test coverage.
For now, I started using
trigger_error()
. Easy enough to change.Comment #35
Wim Leers#2579847: /node/add is lacking cacheability metadata, causes problems when cached by Dynamic Page Cache and "Use admin theme when editing or creating content" is turned off was just committed, that's why #32 failed.
Uploading #32's
do-not-test
patch.Comment #37
dawehnerAre you sure assertRaw is the right way to check that? Don't we have a error handler which detects those errors on test time?
Comment #38
Wim LeersMore accurate title.
Comment #39
Wim Leers#37: I'm certain this is not 100% correct :) That test still fails because that error is triggered; I don't know how to test properly. I know I've fought this in the past too, and there are at most a handful of
WebTestBase
tests dealing with this. Pointers (or reroll) welcome.Comment #44
pwolanin CreditAttribution: pwolanin as a volunteer commentedDoes this really meet the definition of critical (release blocking)?
Comment #45
chx CreditAttribution: chx commentedI absolutely have no idea any more. If we were applying criteria I am familiar with we would have never gotten here: you'd would've never committed so much code that made Drupal slow (when did you see the performance gate stopping any core initiatives?) and then you would never have added such a significant change this extremely late to mitigate the performance catastrophe you (you, this time I won't say we, I refuse to take even partiial responsibility) brought on yourselves. As far as I am concerned, yes, this is critical because if core breaks something as often visited as node/add then what hope contrib / custom has for writing bug free code? None, I believe. But, this is Drupal 8 and what I see and what others see fundamentally differs. So: I do not know.
Comment #46
dawehnerLet's try to be objective. This issue certainly hardens security by making it harder for people to specify non cacheablity information at all.
On the other hand this issue also doesn't solve any actual existing critical security issues, given which places had to be covered. I kinda assume that giving people
more information about filter formats isn't a security issue given that we check access to them on forms.
Comment #47
chx CreditAttribution: chx commentedUnfollowed.
Comment #48
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedIf we can get this in as major, sure fine with me ...
But it is a little big behavior change.
Comment #49
Wim LeersThis will fix another whole bunch.
Comment #50
catchIt should be E_DEPRECATED then it can go in a minor I think.
We don't know that routes without #cache have actual cacheability problems, they might be fine. Also ones that have it might not be.
So it is not an error to not have it, we just prefer you to have it or set no_cache. Deprecation seems about right.
Comment #52
Wim LeersExactly! This is what I'd been pondering yesterday night too: it's not a perfect signal, and so we shouldn't actually hard force this. It should only be a nudge towards developers.
Do you think this can go in a future RC release? AFAICT it could.
Comment #53
catchIf we think it is actual security hardening, then it could probably go in during RC - the patch itself looks low risk.
Whether it's actually helping anything to have empty #cache in controllers to suppress whatever error we add (like the patch adds) is a different question though.
Comment #55
dawehnerThis is hopefully everything.
Comment #56
dawehnerAdded an issue for the same idea, but for blocks: #2584951: Let Block plugins require to set #cache on their render arrays
Comment #58
dawehnerSome less
Comment #59
Studiographene CreditAttribution: Studiographene as a volunteer and commentedComment #64
Wim LeersMore than a year after this was filed, the fear has fortunately not become reality. I think it's safe to close this.
Not sure what the best status is.