8

When Form API generates a form, it also generates a token that is passed out with the form in a hidden field, and expected to be returned back. If it is, the form is processed.

If a rendered form where ever to be cached, say, by Varnish, this mechanism breaks. The first user submitting the form will consume the token, and following attempts to use the form will be rejected.

What strategies are available to keep forms working while caching their rendered form?

10
  • Are you sure about this? I have built sites with forms and reverse proxies and not seen an issue. The only thing you have to watch, in general, is to ensure results pages don't get cached. May 31, 2013 at 11:40
  • I would love to be proven wrong, as that would solve my problem, but yes, I'm sure. :) Check the form_{g,s}et_cache functions for details.
    – Letharion
    May 31, 2013 at 12:24
  • For anonymous users, I am sure that a page with a form can be cached safely. For non-anonymous users, reverse proxies are problematic in any case. May 31, 2013 at 15:41
  • 2
    (Tokens are only generated when a user has an ID.) May 31, 2013 at 15:43
  • 1
    Ah, that makes sense. Unfortunately my users in this case are authenticated. Perhaps the question should be re-worded to include that.
    – Letharion
    May 31, 2013 at 17:54

2 Answers 2

5
+200

I use BOA for my sites, but by default BOA simply disables front end-caching on the fly for form submissions. Beyond my actual experience I came a cross a one year old artificial on how the New Zealand Post deals with Drupal & Varnish and the form token issue. Holy John Wayne, its a must read for Drupal caching -really. Focusing only on the the form issue:

The final piece to our puzzle is the Cookie Cache Bypass Advanced module, which automatically sets a special NO_CACHE cookie whenever the user submits a POST form on the site, including things like the login form. Our Varnish is configured to bypass the page cache (but not the ESI cache) when it sees this cookie.

You can also disable form tokens when XSRF production is not reaquired with in form_alter (unset($form[‘#token’]);) or ($form[‘#token’] = FALSE;)

An Acquia Drupal performance article puts forth a Drupal Module Authcache, but reading the doc on Authcache, it works out the caching with a place holder for the form (not caching the form):

Authcache attempts to intercept any customized content and set up a placeholder within the HTML. Then after the page is loaded, an Ajax callback is used to retrieve custom data and fill in the placeholders, dynamically updating the page HTML.

Current Authcache placeholders: Form tokens (logged-in users only; required by > Drupal to prevent cross-site request forgery attacks)

The strategy is, cache everything but the form. So addressing everything else: Maybe Varnish is not used at all, Memcache & Redis? My strategy would be to use what BOA offers because I use BOA and the wizards behind it (omega8.cc) know a ton more than I. I dont think there is an external cache that solves the problem. They all seem to bypass for the form.

Do partial caching with the aforementioned authcache and with finely tweaked Views and Panels as mentioned in the NZ Post article and described by the brain trust at Wunderkraut - its old, but addresses the issue.

Use Drupal ESI Module and Varnish is partially ESI compliant):

ESI - or Edge Side Includes - is a high performance caching solution for Authenticated users but can be helpful for Anonymous users as well.

Typically, pages which are personalised for authenticated users (even minor personalisations, such as a block which says "Logged in as manarth") will prevent reverse-proxies (which can easily perform 100 times faster than Drupal) from caching the page, because messages intended for one user could then be seen by another.

Hope thats more helpful.

4
  • A quick look at the code suggests the ESI module doesn't do anything at all with regard to form validation; no mention of token handling, nor any interesting form alters. Is it possible you simply haven't cached any forms requiring authentication in varnish, and that's why you've never seen this problem?
    – Letharion
    Jun 7, 2013 at 10:16
  • Turns out that is exactly what is going on , BOA bypasses the front end cache on the fly for forms (sorry for my previously incomplete/wrong answer). ESI is still important part of the "cache everything but" strategy now in my answer even if it doesn't directly solve.
    – Tom
    Jun 7, 2013 at 16:44
  • That NZ post article was indeed really interesting. However, as for as I can tell, it only addresses the token issue with: "In cases where you’re sure that XSRF protection is not important ... Drupal provides a mechanism to disable form tokens", which isn't helpful in my case.
    – Letharion
    Jun 10, 2013 at 9:21
  • Lots of useful information though, and definitely others will be able to apply it to their issues. +1, and since it's only an hour left, I can might as well aware the bounty too. :)
    – Letharion
    Jun 10, 2013 at 10:04
0

One potential solution would be to disable the token all together with $form[‘#token’] = FALSE;, then override the submit callback to instead of actually posting the comment, regenerate the original form with an token, and ask the user to confirm the post.

If the user supports ECMAScript, one could improve the user experience by having a services resource which exposes form generation of new form tokens and inserts the relevant form into the form_cache. Then, as soon as the user focuses on the form, and is thus likely to want to submit it, disable the submit button, fetch a new token and insert it into the already rendered form, and enable the submit button again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.