Varnish VCL - Regular Expression Evaluation

Posted by Hugues ALARY on Server Fault See other posts from Server Fault or by Hugues ALARY
Published on 2012-10-10T21:44:45Z Indexed on 2012/10/12 21:39 UTC
Read the original article Hit count: 351

Filed under:

I have been struggling for the past few days with this problem:

Basically, I want to send to a client browser a cookie of the form foo[sha1oftheurl]=[randomvalue] if and only if the cookie has not already been set.

e.g. If a client browser requests "/page.html", the HTTP response will be like: resp.http.Set-Cookie = "foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=ABCD;"

then, if the same client request "/index.html", the HTTP response will contain a header: resp.http.Set-Cookie = "foo14fe4559026d4c5b5eb530ee70300c52d99e70d7=QWERTY;"

In the end, the client browser will have 2 cookies: foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=ABCD foo14fe4559026d4c5b5eb530ee70300c52d99e70d7=QWERTY

Now, that, is not complicated in itself. The following code does it:

import digest;
import random; ##This vmod does not exist, it's just for the example.


sub vcl_recv()
{
    ## We compute the sha1 of the requested URL and store it in req.http.Url-Sha1
    set req.http.Url-Sha1 = digest.hash_sha1(req.url);
    set req.http.random-value = random.get_rand();
}

sub vcl_deliver()
{
    ## We create a cookie on the client browser by creating a "Set-Cookie" header
    ## In our case the cookie we create is of the form foo[sha1]=[randomvalue]
    ## e.g for a URL "/page.html" the cookie will be foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=[randomvalue]
    set resp.http.Set-Cookie = {""} + resp.http.Set-Cookie + "foo"+req.http.Url-Sha1+"="+req.http.random-value;
}

However, this code does not take into account the case where the Cookie already exists. I need to check that the Cookie does not exists before generating a random value. So I thought about this code:

import digest;
    import random;


sub vcl_recv()
{
    ## We compute the sha1 of the requested URL and store it in req.http.Url-Sha1
    set req.http.Url-Sha1 = digest.hash_sha1(req.url);
    set req.http.random-value = random.get_rand();

    set req.http.regex = "abtest"+req.http.Url-Sha1;

    if(!req.http.Cookie ~ req.http.regex)
    {
        set req.http.random-value = random.get_rand();
    }
}

The problem is that Varnish does not compute Regular expression at run time. Which leads to this error when I try to compile:

Message from VCC-compiler:
Expected CSTR got 'req.http.regex'
(program line 940), at
('input' Line 42 Pos 31)
        if(req.http.Cookie !~ req.http.regex) {
------------------------------##############---

Running VCC-compiler failed, exit 1

VCL compilation failed

One could propose to solve my problem by matching on the "abtest" part of the cookie or even "abtest[a-fA-F0-9]{40}":

if(!req.http.Cookie ~ "abtest[a-fA-F0-9]{40}")
{
    set req.http.random-value = random.get_rand();
}

But this code matches any cookie starting by 'abtest' and containing an hexadecimal string of 40 characters. Which means that if a client requests "/page.html" first, then "/index.html", the condition will evaluate to true even if the cookie for the "/index.html" has not been set.

I found in bug report phk or someone else stating that computing regular expressions was extremely expensive which is why they are evaluated during compilation. Considering this, I believe that there is no way of achieving what I want the way I've been trying to.

Is there any way of solving this problem, other than writting a vmod?

Thanks for your help!

-Hugues

© Server Fault or respective owner

Related posts about varnish