By default Varnish doesn't cache requests with a Cookie header:
http://varnish-cache.org/svn/trunk/varnish-cache/bin/varnishd/default.vcl
sub vcl_recv {
(...)
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (lookup);
You need to code the behaviour you want into the configuration. Be aware that the Cookie is part of the client request, not the "page" (object, really). The "page" (object) comes with a "Set-Cookie" header - that's the one that will be cached.
Also, "Vary: Cookie" doesn't mean "do not cache". It means cache one object for every value of Cookie received.
If your application doesn't generate any content based on Cookie, it's probably safe to ignore it:
- if (req.http.Authorization || req.http.Cookie) {
+ if (req.http.Authorization) {
Do some tests and you will get the hang of it. Hope this helps.
Since all the cookies - both name and value - are in the req.http.Cookie
string, you should be able to check for both name and value at the same time. Unfortunately, Varnish does not have any specialized methods for dealing with cookies - you must use regular expressions.
It is important to note that cookies are delimited by a semicolon and white space, for example:
cookie1=abc; cookie2=def
We know, therefore that our cookie is either at the start of req.http.Cookie, or is preceded by a semicolon and white space, and either ends with a semicolon, or is at the end of req.http.Cookie. Given this, we can construct a regex that will match our cookie and the semicolon, if any. Something like:
(^|;\s*)(Lang=En)(;|$)
Briefly, going through the above we have:
- First set of brackets - match the start:
^
means start of string
|
means OR
;
is taken literally (i.e. semicolon)
\s
means white space
*
means one or more repetitions of the preceding character
- Summary: either the start of the string or a semicolon followed by white space
- Second set of brackets - match the cookie:
Lang
is the name of the cookie
En
is the value of the cookie
- Third set of brackets - match the end
;
is taken literally (i.e. semicolon)
|
means OR
$
means end of string
- Summary: either a semicolon or the end of the string
Using the above, we can check for the cookies and perform some action on them:
if (req.http.Cookie ~ "(^|;\s*)(Lang=En)(;|$)"){
//do something with En
} elseif (req.http.Cookie ~ "(^|;\s*)(Lang=Fr)(;|$)") {
//do something with Fr;
}
There may be better ways, or more efficient regexes (unfortunately, varnish doesn't have user defined variables - which means you can't use regex capture groups) - but hopefully this will do the job.
Arguably, you could construct a regex with a capture group using regsub, and set that as a subdomain, perhaps something like:
set req.url = regsub(req.http.Cookie, "(?:^|;\s*)(?:Lang=(.*?))(?:;|$)", "\1.")+"example.com";
In the case of 'Lang=en', you would capture the 'en' add a period (.) and prepend to 'example.com' giving you en.example.com. I'd suggest though directly using a cookie to set the URL - without a lot of error checking - would be a very bad solution. If you just have 3 languages, a couple of if statements and a default would be much safer.
Note: the above is untested, and regexes aren't my forte - expect a few mistakes - but hopefully the premise works.
Best Answer
Yeah, just use a regex in vcl_recv. Something like: