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