Split off from
- #606840-26: Enable internal page cache by default
- #606840-31: Enable internal page cache by default
- #606840-39: Enable internal page cache by default
Quoting @catch in #606840-39, to capture what still needs to be done:
with contact module I don't think the problem is that flood control is incompatible with page caching, instead it's that flood control needs to be handled in validate/submit, not when viewing forms.
Quoting #606840-26: Enable internal page cache by default, to capture what this patch does and why:
The failures there are because a 403 is expected, but a 200 is given. The 403 is expected because a permission is revoked from the anonymous users role.
The requested URL corresponds to the
entity.user.contact_form
route. That route's access checking uses theContactPageAccess
access check. The cache tags associated with that route-level access result must be reflected by the cache tags on the eventual response — otherwise the page cache item for that response will not be invalidated when the cache tags associated with the access result are invalidated.
This is a problem we knew we were going to have to solve at this point, and I think it makes sense to solve it here :)Looking at the other two tests in the Contact module that are failing, similar problems exist. The 4 other failing tests in Contact module are due to flood control not working. That's another bug this issue has uncovered: flood control does *not* work for anonymous users when the page cache is on. The solution is simple: if flood control is active, then don't cache the page. Ideally, we'd communicate this with
#cache['max-age'] === 0
. But until #2443073: Add #cache[max-age] to disable caching and bubble the max-age lands, we'll have to use the page cache kill switch.
Comment | File | Size | Author |
---|---|---|---|
#42 | contact_forms_cacheability_and_flood-2453341-42.patch | 12.74 KB | Wim Leers |
Comments
Comment #1
Wim LeersFirst: rerolling the original patch, which didn't fix Contact module's problematic flood control implementation.
Comment #2
Wim LeersThis change would not be necessary if we choose to do #2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?").
Comment #3
Wim LeersPorting the fix from #606840-35: Enable internal page cache by default.
Comment #6
Wim LeersNext, do #606840-39: Enable internal page cache by default, as described in the IS.
Comment #7
Wim LeersFixed the test failures.
And removed the hunk in
CommentForm
that snuck in, @moshe pointed that out in chat.Now I'll do what I said in #6.
Comment #8
effulgentsia CreditAttribution: effulgentsia at Acquia commented"Needs work" per last sentence in #7.
Comment #9
Wim LeersFor #2, I think this should be blocked on #2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?").
But, still doing #6.
Comment #10
Wim LeersDid #6: flood control is now performed when validating the message form, instead of when viewing the form.
Comment #11
dawehnerLooks pretty reasonable.
Comment #13
Wim LeersChasing HEAD.
#11: Thanks for the review!
Comment #14
Wim LeersI'll continue with this in the morning.
Comment #15
Wim LeersPer #2428703-11: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?"), looks like that's going to be stuck on discussion for a while, we should try to continue here in the direction that catch prefers: make
AccessResult
responsible for adding the necessary role cache tags. Then if we still do #2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?"), it can be cleaned up there.Comment #17
Wim LeersFixed those failures. Had to introduce a mocked container in 4 more PHPUnit tests. Ugly, but the only way to do it until #2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?") lands.
Comment #18
Wim LeersI just moved the route access result hunks from this patch into #2458349: Route's access result's cacheability not applied to the response's cacheability, so we can get that in separately.
Comment #19
Wim LeersComment #20
larowlanWhat happens if the AccessResult doesn't relate to the current logged in user? Isn't there places where we can formulate an AccessResult based on another user? e.g. anywhere we do an access check we can pass an optional account, with default falling back to the logged in user. If so, that would mean that a) this isn't correct and b) the user should be passed along to the access result and we don't need the call out to the container? Happy to be wrong on this.
nit: two .
Could we move the duplicated code to a trait and then we only need to add a use statement, with the only change to the ::setUp being a call to the trait method? Saves the duplication.
Comment #21
Wim LeersThank you very much for the review!
Sadly, point 1 means that the signature of
::cachePerRole()
would have to change. That means changing all::cachePerRole()
callers.But #2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?") is moving forward again, in a promising direction, since #16. The changes there would completely overlap with this. And the changes there would actually remove the need for many changes in this issue. Therefore, sadly, postponing this issue on that one.
Comment #22
Wim Leers#2428703: Add a 'user.permissions' cache context (was: "Should cache contexts be able to associate a cache tag?") landed, but went in a different direction. Yet it still paved the way for this issue :)
Comment #23
Wim LeersI said in #21:
And my prediction was right. I don't need to fix #20.1 and #20.3, because those hunks are now completely gone :)
This patch is now basically half the size of the previous patch. Note that the interdiff doesn't show everything because some changes were actually part of the rebase conflict.
Comment #24
Wim LeersSuch noob.
Comment #25
Wim LeersBesides, this is actually blocked on #2458349: Route's access result's cacheability not applied to the response's cacheability, which handles about half of this patch.
Comment #26
Wim LeersRerolled on top of #2458349: Route's access result's cacheability not applied to the response's cacheability.
Please keep this postponed until the other issue lands; after it lands, we can mark this issue as NR and it'll be tested.
Comment #27
andypostSo maybe better to move that check to access handler, we should not show the form and try to serve POST requests for "flood"
Comment #28
Wim Leers#27: catch told me to it this way:
See #606840-39: Enable internal page cache by default.
Comment #29
Fabianx CreditAttribution: Fabianx for Drupal Association commentedI agree with #28, the validation message comes when trying to post more not when going to the site.
The code changes for the contact flood changes look good to me.
Comment #30
Wim Leers#2458349: Route's access result's cacheability not applied to the response's cacheability landed. Let's get #26 tested.
Comment #32
Wim LeersThe PHP7 String changes that were committed lately caused conflicts. Rerolled.
Comment #33
larowlannitpick: any reason why strlen and not
!= ''
?Apart from that (or even including that) rtbc
Comment #34
BerdirThat, or just switch has() to get(). That's exactly the difference between the two, has is isset(), if (get()) is basically an !empty(), it will return an empty string, that will be cast to FALSE and it won't go inside the if.
Looks fine to me as well. For the record, I'm pretty sure it would have worked if you just changed to submit in the tests because the form post would run through the uncached controller and should have triggered validation there, but this is cleaner and more reliable if we ever switch to using a separate route or so for form submissions.
Comment #35
Wim LeersApplied the #34 suggested fix. RTBC per #33 & #34.
Comment #36
alexpottNeeds a reroll..
I'm not particularly happy happy about the concept of http headers with no value. Something feels really off. Discussed with @Wim Leers in IRC. We decided that we'll open a followup to discuss how to prevent this.
Comment #37
Wim LeersFollow-up filed: #2463697: X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers should not indicate emptiness by the empty string as header value.
Rerolled.
Thanks to #2453059: Set default render cache contexts: 'theme' + 'languages:' . LanguageInterface::TYPE_INTERFACE having landed in the mean time, in core there's never going to be the case that either of those headers are empty (at minimum,
X-Drupal-Cache-Tags
equals'rendered'
, andX-Drupal-Cache-Contexts
equals'languages:language_interface theme'
).So, we can omit those changes now, and discuss all of that in #2463697: X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers should not indicate emptiness by the empty string as header value.
Comment #38
Wim LeersOops, the rebase was wrong. The rebase interdiff even shows that.
Comment #39
Fabianx CreditAttribution: Fabianx for Drupal Association commentedRTBC + 1 to #38
Comment #40
Fabianx CreditAttribution: Fabianx for Drupal Association commentedI take that back, I don't think the rebase was wrong.
I think #38 misses parts of #35 now.
E.g. the flood and dateFormatter are with #35 removed from the ContactController, but in #38 those remain.
I am confused ...
Comment #42
Wim LeersWell-spotted. #35 indeed removed far more, and the rebase in #37 lost many deletions. I got confused by what I saw, I saw the constructor still getting some interfaces, but those interfaces not being imported, so I "fixed" that in #38. So now all the intended deletions were no longer there. Now they're back :)
Comment #43
Fabianx CreditAttribution: Fabianx for Drupal Association commentedRTBC, this now looks great!
Comment #44
alexpottI gave some thought to the change of making flood control on the validate since this is a change to how users experience the site - i.e.they'll only get informed on submit instead of just visiting the page. I think this an acceptable price for a cacheable site so +1.
This issue addresses a major bug and is allowed per https://www.drupal.org/core/beta-changes. Committed eebf493 and pushed to 8.0.x. Thanks!
Comment #46
Fabianx CreditAttribution: Fabianx for Drupal Association commentedDo we need a change record / doc update of some kind to inform other authors to ensure they use flood correctly?
Comment #47
effulgentsia CreditAttribution: effulgentsia at Acquia commentedYes, I think so.
Comment #48
Wim LeersBasically to warn/inform existing contrib modules about the correct usage of Flood?
Comment #49
effulgentsia CreditAttribution: effulgentsia at Acquia commentedRight, to:
- inform site builders about the change to site behavior with respect to Contact module
- inform contrib modules that create their own flood-controlled forms about the new best practice
- inform modules that extend/alter Contact and/or other forms and might care about this (e.g., Mollom?)
Comment #50
Wim LeersDone: https://www.drupal.org/node/2464873.
Comment #51
andypostCR looks great
Comment #52
cosmicdreams CreditAttribution: cosmicdreams commentedDoes this need to be ported to Drupal 7?