Problem/Motivation
You can check for and do something based on ?some_arg, amp.module currently uses that to trigger the AMP-mode with ?amp.
It also tries to be nice and adds the cache context for it. It looks like it works, but that's only the case because it also triggers a theme switch. It has a second argument, ?warnfix that allows to show warnings and that doesn't work.
Took us a while to track it down...
Proposed resolution
Return a special value for an empty but existing argument, something like :empty:. There is a theoretical risk of a clash where an empty and a query argument with that value are the same, but that seems highly unlikely since such arguments are only useful as binary flags I think.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#31 | 2729439-31.patch | 3.85 KB | Wim Leers |
Comments
Comment #2
Wim LeersInstead of
:empty:
, I'd suggest using a value that you cannot actually send in a query argument in any sane way. Such as?empty?
, or?valueless?
.Comment #3
Wim LeersSo, this basically?
Comment #4
Wim LeersNow 90% less stupid.
Comment #5
Wim LeersThis blocks #2688545: Remove ampNodeViewController in favor of amp_entity_view_alter().
Comment #7
Berdir90% less stupid is unfortunately not enough :)
Now it doesn't vary between not set at all and empty. You need get, if that's empty, check has() and then either ?valueless? or nothing
Comment #8
Wim LeersAnd test coverage. Which showed that the 90% less stupid was accurate: it was not 100% less stupid. This is.
Comment #11
BerdirAs written in IRC, this can't work as you still have the old return in place ;)
This should be a lot easier to read if you just this an elseif (.. has()) and then the ternary.
The return NULL is implicit then.
Comment #12
olli CreditAttribution: olli commented#2509436: Make CachePluginBase::generateResultsKey() to pass valid data to CacheContextsManager::convertTokensToKeys looks related, patch #25 would return 'arg=' for ?arg.
Comment #13
Wim LeersGAHHHHHHHHHH. My computer is acting seriously weird: https://twitter.com/wimleers/status/733340751665504256. I was testing to verify that tests were failing as expected with the old behavior. And now that ended up in the proper patch. Sigh.
Fixing.
Comment #14
Wim LeersComment #17
BerdirRandom fail?
Comment #18
Wim LeersGreen now, so random fail indeed.
Berdir pointed out in IRC this can be even simpler.
I think this is now really ready for RTBC.
Comment #19
BerdirLets see if testbot agrees ;)
Comment #20
RainbowArrayWorth noting that if somebody only needs the query argument with no value (?somearg), this patch will create a cache variation if ?somearg is present, versus it not being present. However it will also create cache variations if somebody adds a value to that arg, e.g. ?somearg=1, ?somearg=2 ... ?somearg=30000. If those arg values are meaningless, that's a lot of extra cache variations that aren't necessary.
One option to address that would be to create an additional cache context, something like ['query_empty_arg:argname'], with something like the following:
That would ensure that if somebody wants to explicitly set up an argument that will never have a value, that any values entered will be ignored.
I'd suggest doing that in addition to the above patch, not instead of, because the current behavior prior to this patch can be pretty confusing when an empty arg doesn't cause any cache variations.
Comment #21
Wim LeersI'm not convinced this is actually necessary, because you can always bypass caches (including even Page Cache and Varnish!) by adding random URL query arguments.
I personally don't want to make cache contexts more complex than necessary for little or no benefit. But, if a convincing argument can be made, then sure, but let's do that in a different issue then :)
Comment #22
RainbowArrayMy concern is not that adding values to query args (that are supposed to be empty) allows you to bypass cache. The issue is that somebody could spam a site with lots of requests with meaningless arg values and bloat up the cache in the db with unnecessary cache variations.
Comment #23
Wim Leersand
are the same thing!
I should've worded it better. You're bypassing the cache in that the existing cache entries are already exactly what you want. But because Drupal cannot ever know that additional query arguments won't cause different variations, Page Cache will always create a new cache entry. So even just with
drupal.org?random=<random number between 1 and 1 billion>
, you can easily DDoS any Drupal site. This is common knowledge. It's been around for more than a decade. And it's true for just about any CMS out there.Comment #24
RainbowArrayFair point. Let's just get this in then.
Comment #25
neclimdulThis no longer always has an explicit return point. Relying on a default return of NULL seems to "work" here but isn't a good practice and can end up looking like a bug later. Not something we should be in the habit of doing.
Comment #26
Wim Leers#25: heh, this is exactly what @Berdir suggested :P Dammit!
Fixed that nit.
Comment #27
catchJust to say #23 is right, there's no way around this. #2697795: [meta] Cache storage in database can fill the disk, especially via 404s and related issues discuss potentially lowering the ttl for unbounded cache contexts in order to protect a bit against disk filling though - since it can affect the render cache generally as well as page cache.
Comment #28
olli CreditAttribution: olli commented'?value=0' would return '?valueless?'?
Comment #29
Wim LeersYou're right. Great catch.
Comment #30
Wim LeersAdds test coverage proving #28 is right, which means the prior patches still had an uncovered edge case.
PHP--
PHP--
PHP--
Comment #31
Wim LeersAnd here's the fix.
Comment #32
BerdirGood catch.
Comment #35
Wim LeersRandom fail in migrate:
Comment #36
catchI feel bad asking this, but if I was looking through cache keys and saw ?valueless? I'd probably wonder where that came from. Would ?null? be more self-explanatory? If the answer is 'no' that's fine - leaving at RTBC.
Comment #37
Wim LeersI don't care. I found "empty" very confusing, so I went with "valueless". If you prefer "null", that works for me.
Comment #40
catchMeh I also don't care.
Committed/pushed to 8.2.x and cherry-picked to 8.1.x. Thanks!
If this ever is a problem for someone, it's only the value of the context, so could be changed whenever.
Also you might infer from null that the query argument isn't there - i.e. that we're logging it's absence, not that it's there but without a value. So valueless works for that. It's an !isset() vs. !array_key_exists() problem.
Comment #41
Wim LeersYep.
Thanks for the commit!
Comment #42
andypostFiled related issue for headers context #2738563: Headers cache context does not work, also needs test coverage
Comment #43
andypostAlso that needs follow-up for values that could be array, I'm using "," to split them
Comment #44
andypostHere's another follow-up #2744421: QueryArgsCacheContext::getContext() may return NULL, violates the interface
The result of
\Drupal\Core\Cache\Context\QueryArgsCacheContext::getContext()
should not be *NULL*