Skip to content

var: var.get() of an unset variable is != "" #229

@delthas

Description

@delthas

Hi,

Consider the following VTC, testing behavior of unset and empty variables:

varnishtest "Test var.get() truthiness and equality to the empty string"

server s1 {
       rxreq
       txresp
} -start

varnish v1 -vcl+backend {
	import std;
	import var from "${vmod_builddir}/.libs/libvmod_var.so";

	sub vcl_deliver {
		var.set("empty", "");
		if (var.get("empty")) {
			set resp.http.empty-truthy = "true";
		} else {
			set resp.http.empty-truthy = "false";
		}
		if (var.get("empty") == "") {
			set resp.http.empty-empty = "true";
		} else {
			set resp.http.empty-empty = "false";
		}
		if (var.get("unset")) {
			set resp.http.unset-truthy = "true";
		} else {
			set resp.http.unset-truthy = "false";
		}
		if (var.get("unset") == "") {
			set resp.http.unset-empty = "true";
		} else {
			set resp.http.unset-empty = "false";
		}
	}
} -start

client c1 {
	txreq -url "/"
	rxresp
	// Empty is truthy: ("String types will evaluate to false if they are unset.")
	expect resp.http.empty-truthy == "true"
	// Empty is empty:
	expect resp.http.empty-empty == "true"
	// Unset is not truthy: ("String types will evaluate to false if they are unset.")
	expect resp.http.unset-truthy == "false"
	// Unset is empty: ("if (req.http.opthdr == "") {} does not distinguish if the header does not exist or if it is empty.")
	expect resp.http.unset-empty == "true"

	// The last test above fails, because `resp.http.unset-empty` is actually "false", because `var.get("unset") == ""` returns false.
} -run

var.get("unset") == "" of an unset variable returns false, which is unintuitive given the VCL reference documentation:

String types will evaluate to false if they are unset. This allows checks of the type if (req.http.opthdr) {} to test if a header exists, even if it is empty, whereas if (req.http.opthdr == "") {} does not distinguish if the header does not exist or if it is empty.

The reference suggets that var.get("unset") == "" should return true (does not distinguish if the header does not exist or if it is empty). But it actually returns false.

This means that a user of libvmod-var that wishes to check a variable for "not empty" shouldn't do var.get("foo") != "" but actually var.get("foo") && var.get("foo") != "".

I suppose this cannot easily be fixed without "breaking" the API. Should this be documented?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions