Varnish VCL - Regular Expression Evaluation
- by Hugues ALARY
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