Ipstenu / varnish-http-purge

Proxy Cache Purge
Apache License 2.0
46 stars 47 forks source link

How to purge URLs that contain language cookies? #68

Closed gerdneuman closed 6 years ago

gerdneuman commented 6 years ago

Some hosters (ours is Gandi.net) offer a varnish based caching solution where you can use Cookies as part of the cached object. For instance, Pantheon and gandi.net Simple Hosting offer this using specially prefixed cookies. This is needed for instance for language cookies like Polylang or WPML use (search for "cookie" in https://polylang.pro/doc/php-constants/ and https://polylang.pro/doc/detect-the-browser-preferred-language/)

Whithout this cookie allowed by varnish, pages could not be cached here.

But this also has the downside, that when you want to purge such a page then

Use case:

We use Polylang and have STYXKEY_pll_language cookie which can be unset (no language set yet), de for German or en for English. So a URL gets cached in possibly 3 different variants.

How caching works for this use case:

  1. When caching the page by calling the following (browser does the same), we make sure this page gets cached inside varnish with:
curl -v -s 'https://www.mysite.de/de/shop/' -o /dev/null
curl -v -s 'https://www.mysite.de/de/shop/' -H 'Cookie: STYXKEY_pll_language=de' -o /dev/null
curl -v -s 'https://www.mysite.de/de/shop/' -H 'Cookie: STYXKEY_pll_language=en' -o /dev/null

Now when you want to PURGE a page, you need to call it this way:

 curl -X PURGE https://www.mysite.de/de/shop/ 
 curl -X PURGE https://www.mysite.de/de/shop/ -H 'Cookie: STYXKEY_pll_language=de'
 curl -X PURGE https://www.mysite.de/de/shop/ -H 'Cookie: STYXKEY_pll_language=en'

I asked our hoster Gandi.net if a normal PURGE could not purge all 3 variants, but they said no because that this is the way varnish works the way here, and if I want to PURGE all variants then I'd have to call it this way three times.

Problem: There's no way to do this currently given the available filters by the varnish-http-purge plugin. There's varnish_http_purge_headers which could be used to set the Cookie header, but then it would be always called once and with the same kind. But we would need to have 3 different cookie headers: once none, once with de and once with en.

I thought a night over this and think I would go with this hacky workaround:

  1. Set a filter on vhp_purge_urls using our child theme.
  2. Within the filter do the purging on ourselves by doing more or less the same using wp_remote_request as the plugin does:

https://github.com/Ipstenu/varnish-http-purge/blob/b2c13647cd56dfbc23212d8615e78046075fad3e/varnish-http-purge.php#L619-L622

  1. Then always return an empty array back to vhp_purge_urls so that the plugin does just nothing.

What do you think of this approach? I am especially wondering if in step 3 it is enough to just return an empty array to stop varnish-http-purge from executing any further.

In the long run, of course, I would be interested if there was a filter that would be possible to use for this. The above would be a shortterm hack/workaround. Hence opening this issue for tracking too.

Ipstenu commented 6 years ago

I take it using -H 'Cookie: STYXKEY_pll_language=*' as a wild card doesn't work then?

Do you ALWAYS update all three pages at once? I don't use Polylang so I'm unfamiliar as to if it updates one language at a time or not

gerdneuman commented 6 years ago

I take it using -H 'Cookie: STYXKEY_pll_language=*' as a wild card doesn't work then?

No, that would not be working because cookies are always key: value and there's no wildcard notation. So * would be just a value for the key STYXKEY_pll_language, also from the perspective of varnish AFAIK.

Do you ALWAYS update all three pages at once?

Yes. (Not sure if there would be use cases when you'd only be invalidating for certain cookie values, but in our use case we invalidate always).

I don't use Polylang so I'm unfamiliar as to if it updates one language at a time or not

Yeah, Polylang can be configured in many different ways: Two scenarios would be browser language detection or how the URLs/domains are setup. So it's easy to adapt, but all use cases usually involve the language cookie.

But in the end most language plugin for other CMSs like Drupal or Plone (which I both know) work the same: Having a language cookie to persist (and remember) the user's language choice. It's a common pattern, and Polylang is not different here.

gerdneuman commented 6 years ago

I implemented this now the way as described above and it works nicely. Not sure how this could be done in any other simple way by another filter, so let's close this now :)