Header set to NULL by a VMOD: semantic change between 3.0.3 and 3.0.6
Geoff Simmons
geoff at uplex.de
Mon Nov 3 15:21:33 CET 2014
Hello all,
We're presently testing an upgrade from Varnish 3.0.3 to 3.0.6, and have
encountered a change in the semantics of a header evaluated in boolean
context after the header has been set to NULL by a VMOD.
The attached VTC test passes on 3.0.3 and fails on 3.0.6.
The VMOD in question is header, but I suspect the same thing will happen
with any VMOD that returns NULL for a STRING return type.
Ordinarily, if a header does not exist, then the bare header expression
evaluates to false in boolean context:
# This condition is false if there is no request header Foo
if (req.http.Foo) {
/* do stuff ... */
}
A VMOD may return NULL for a function whose return type is STRING;
header.get() does this if it does not find a header named in the first
arg that matches the expression in the second arg:
# header.get() returns NULL if there is no Cookie header that matches
# "bar"
import header;
set req.http.X-Bar-Cookie = header.get(req.http.Cookie, "bar");
If that happens in Varnish 3.0.3, then the header set on the LHS of the
assignment evaluates to false in boolean context, but it evaluates to
true in Varnish 3.0.6:
# if req.http.X-Bar-Cookie was set to NULL above,
# then this condition is false in 3.0.3, but true in 3.0.6
if (req.http.X-Bar-Cookie) {
/* do stuff ... */
}
A workaround is to match the header against the one-char/any-char regex:
# if req.http.X-Bar-Cookie was set to NULL above,
# then this condition is false in both 3.0.3 and 3.0.6
if (req.http.X-Bar-Cookie ~ ".") {
/* do stuff ... */
}
But it's wasteful to have to turn on the regex matcher just to check for
the existence of a header.
I don't see anything about this in the change logs between 3.0.3 and
3.0.6, and haven't had a chance to look through changes in source to
spot what causes the difference. Of course my guess may be wrong, and
this is just an issue with the header VMOD; but it seems more likely to
be an unintentional change in the meaning of NULL in VRT.
@devs: Should I file a trac ticket?
Sorry that I don't have an example with 4.x yet (because I'm having
trouble getting the header VMOD to build with 4.x; and in any case, it
would be a different implementation of the VMOD then).
Best,
Geoff
--
** * * UPLEX - Nils Goroll Systemoptimierung
Scheffelstraße 32
22301 Hamburg
Tel +49 40 2880 5731
Mob +49 176 636 90917
Fax +49 40 42949753
http://uplex.de
-------------- next part --------------
varnishtest "Non-existent header returned from header.get()"
server s1 {
rxreq
expect req.url == "/"
txresp -hdr "Bar: baz"
} -start
varnish v1 -vcl+backend {
import header;
sub vcl_deliver {
if (req.http.X-Foo ~ ".") {
set resp.http.X-Match-Foo = "true";
}
else {
set resp.http.X-Match-Foo = "false";
}
if (req.http.X-Foo) {
set resp.http.X-Boolean-Foo = "true";
}
else {
set resp.http.X-Boolean-Foo = "false";
}
set req.http.X-Quux = header.get(req.http.Bar, "quux");
if (req.http.X-Quux ~ ".") {
set resp.http.X-Match-Quux = "true";
}
else {
set resp.http.X-Match-Quux = "false";
}
if (req.http.X-Quux) {
set resp.http.X-Boolean-Quux = "true";
}
else {
set resp.http.X-Boolean-Quux = "false";
}
return(deliver);
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.X-Foo == <undef>
expect resp.http.X-Match-Foo == "false"
expect resp.http.X-Boolean-Foo == "false"
expect resp.http.Bar == "baz"
expect resp.http.X-Quux == <undef>
expect resp.http.X-Match-Quux == "false"
expect resp.http.X-Boolean-Quux == "false"
} -run
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <https://www.varnish-cache.org/lists/pipermail/varnish-misc/attachments/20141103/8751ed30/attachment.pgp>
More information about the varnish-misc
mailing list