How do you let a call through in varnish when a cookie "lang" is not set?

Solution 1:

Bypassing the cache when a lang cookie was not set

In its most basic form, this is the VCL code you need to pass requests to the backend that don't contain a lang cookie:

sub vcl_recv {
    if(req.http.Cookie !~ "(^|([^;]*;)+)\s*lang=([^;]*)\s*($|(;[^;]*)+)") {
        return(pass);
    }
}

However, you'll probably need to define some logic in case the lang cookie was set.

Using the value of the lang cookie

The following VCL snippet extracts the language that was set by the lang cookie and stores it in req.http.lang.

This value is used to create a cache variation per language:

sub vcl_recv {
    if(req.http.Cookie !~ "(^|([^;]*;)+)\s*lang=([^;]*)\s*($|(;[^;]*)+)") {
        return(pass);
    } 
    set req.http.lang = regsub(req.http.Cookie,"(^|([^;]*;)+)\s*lang=([^;]*)\s*($|(;[^;]*)+)","\3");
    //Some other logic
    return(hash);
}

sub vcl_hash {
    if(req.http.lang) {
        hash_data(req.http.lang);
    }
}

The snippet above also explicitly calls return(hash). At some point you will need to force Varnish to cache when the lang cookie is set, because the standard Varnish behavior cache anything when cookies are present.

I added a //Some other logic comment, because I'm assuming there will be more logic to bypass the cache. For example when request methods other than GET and HEAD are used, or for custom URL patterns that need to bypass the cache.

Avoiding too many cache variations

The hash_data(req.http.lang) statement will ensure that a cache variation is created for every value that the lang cookie may have.

The danger with that is that users with bad intentions start adding random values to the lang cookie to fill the cache.

Keeping this risk in mind, it would make sense to explicitly list the supported languages in your regular expression.

Here's the initial regex:

(^|([^;]*;)+)\s*lang=([^;]*)\s*($|(;[^;]*)+)

Here's an example with hardcoded supported languages:

(^|([^;]*;)+)\s*lang=(en|es|de|it|es|fr|nl)\s*($|(;[^;]*)+)

Just tailor this regex to your needs and the languages your web platform supports.