<div>Hi there, </div><div><br></div><div>I have been struggling for the past few days with this problem:</div><div><br></div><div>Basically, I want to send to a client browser a cookie of the form <font face="courier new, monospace">foo[sha1oftheurl]=[randomvalue]</font>. If and only if the cookie has not already been sent.</div>
<div><br></div><div>e.g. If a client browser requests <font face="courier new, monospace">"/page.html"</font>, the HTTP response will be like:</div><div><font face="courier new, monospace">resp.http.Set-Cookie = "foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=ABCD;"</font></div>
<div><br></div><div>then, if the same client request <font face="courier new, monospace">"/index.html"</font>, the HTTP response will contain a header:</div><div><font face="courier new, monospace">resp.http.Set-Cookie = "foo14fe4559026d4c5b5eb530ee70300c52d99e70d7=QWERTY;"</font></div>
<div><br></div><div>In the end, the client browser will have 2 cookies:</div><div><font face="courier new, monospace">`foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=ABCD`</font></div><div><font face="courier new, monospace">`foo14fe4559026d4c5b5eb530ee70300c52d99e70d7=QWERTY`</font></div>
<div><br></div><div><br></div><div>Now, that, is not complicated in itself. The following code does it:</div><div><br></div><div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>import digest;</font></div>
<div><font face="courier new, monospace"> import random;</font></div><div><font face="courier new, monospace"><br></font></div><div><span style="white-space:pre-wrap"><font face="courier new, monospace"> </font></span></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>sub vcl_recv()</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>{</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>## We compute the sha1 of the requested URL and store it in req.http.Url-Sha1</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>set req.http.Url-Sha1 = digest.hash_sha1(req.url);</font></div>
<div><font face="courier new, monospace"> set req.http.random-value = random.get_rand();</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>sub vcl_deliver()</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>{</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>## We create a cookie on the client browser by creating a "Set-Cookie" header</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>## In our case the cookie we create is of the form foo[sha1]=[randomvalue]</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>## e.g for a URL "/page.html" the cookie will be foo4c9ae249e9e061dd6e30893e03dc10a58cc40ee6=</font><span style="font-family:'courier new',monospace">[randomvalue]</span></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>set resp.http.Set-Cookie = {""} + resp.http.Set-Cookie + "foo"+req.http.Url-Sha1+"="+req.http.random-value;</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div></div><div><br></div><div><br></div><div>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:</div>
<div><br></div><div><div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>import digest;</font></div><div><font face="courier new, monospace"> import random;</font></div>
<div><font face="courier new, monospace"><br></font></div><div><span style="white-space:pre-wrap"><font face="courier new, monospace"> </font></span></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>sub vcl_recv()</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>{</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>## We compute the sha1 of the requested URL and store it in req.http.Url-Sha1</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>set req.http.Url-Sha1 = digest.hash_sha1(req.url);</font></div></div></div><div><span style="font-family:'courier new',monospace"> set req.http.random-value = </span><span style="font-family:'courier new',monospace">random.get_rand();</span></div>
<div><span style="font-family:'courier new',monospace"><br></span></div><div><font face="courier new, monospace"> set req.http.regex = "abtest"+req.http.Url-Sha1;</font></div><div><div><font face="courier new, monospace"><br>
</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>if(!req.http.Cookie ~ req.http.regex)</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>{</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>set req.http.random-value = random.get_rand();</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div></div><div><br></div><div><br></div><div>The problem is that Varnish does not compute Regular expression at run time. Which leads to this error when I try to compile:</div>
<div><font face="courier new, monospace"><br></font></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><font face="courier new, monospace">Message from VCC-compiler:</font></div></div><div><div>
<font face="courier new, monospace">Expected CSTR got 'req.http.regex'</font></div></div><div><div><font face="courier new, monospace">(program line 940), at</font></div></div><div><div><font face="courier new, monospace">('input' Line 42 Pos 31)</font></div>
</div><div><div><font face="courier new, monospace"> if(req.http.Cookie !~ req.http.regex) {</font></div></div><div><div><font face="courier new, monospace">------------------------------##############---</font></div>
</div><div><div><font face="courier new, monospace"><br></font></div></div><div><div><font face="courier new, monospace">Running VCC-compiler failed, exit 1</font></div></div><div><div><font face="courier new, monospace"><br>
</font></div></div><div><div><font face="courier new, monospace">VCL compilation failed</font></div></div></blockquote><div><br></div><div>One could propose to solve my problem by matching on the "abtest" part of the cookie or even "abtest[a-fA-F0-9]{40}":</div>
<div><br></div><div><div><font face="courier new, monospace"> if(!req.http.Cookie ~ "abtest[a-fA-F0-9]{40}")</font></div></div><div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>{</font></div>
<div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>set req.http.random-value = random.get_rand();</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div>
</div><div><br></div><div>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.</div>
<div><br></div><div>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.</div>
<div><br></div><div>Is there any way of solving this problem, other than writting a vmod?</div><div><br></div><div>Thanks for your help!</div><div><br></div><div>-Hugues</div>