Fastly VCL check if value exists, is set

What is the recommended way to check if a value is set?

TL;DR
Jumping to the answer, I believe these examples would work:

if ( req.http.cookie ~ ".") {
  return(pass);
}

or

if ( req.http.cookie != "") {
  return(pass);
}

Either of these call return(pass) if the value req.http.cookie is set.


However, going back to a first attempt, the most surprising result was this always evaluated to TRUE.

if ( req.http.cookie ) {
  return(pass);
}

50% of the reason for that is explained in VCL best practices | Fastly Documentation that “Empty strings are always truthy”.

However what if req.http.cookie is “not set”, and verified to be (null) . That should return FALSE, right? No, guess what happens. The if statement seems to convert req.http.cookie from (null) to empty string. Now it’s really empty string. And then it’s TRUE (empty strings are truthy).

Next,

if ( req.http.cookie == null) {

and

if ( req.http.cookie == (null)) {

Cause errors. They are not solutions.

This one,

if ( req.http.cookie != "") {
  return(pass);
}

is sort of surprising. When req.http.cookie is (null) or “not set”, that is a value which is slightly different from an empty string “”. Similar, but not the same.

Yet in this particular comparison, (null) or “not set” is considered equivalent to empty string “”. req.http.cookie isn’t modified. It remains (null) afterwards.

1 Like

That’s weird, and not how it’s supposed to work! I just wrote a fiddle to check and I get the behaviour I expect, ie. if there is no cookie header, then req.http.cookie is not truthy:

https://fiddle.fastly.dev/fiddle/f0fca017

It’s correct to say that if ( ... ) is a reasonable way to check whether something is set (it’s not meaningful in VCL to check whether something exists because your code won’t compile if you reference a non-existent variable), and if something is not set, it should be falsey.

If you can do a fiddle to reproduce a case where a not set variable is truthy please do share it, and we will look into it more.

Andrew

You are right!

The rest of the VCL wasn’t empty. It had additional code to remove analytics tokens.

set req.http.Cookie = regsuball(req.http.Cookie, "_ga[^=]*=[^;]+(; )?", "");  
...

regsuball converts (so to speak) null into empty string. After that it was actually an empty string, so the rest of the results were unexpected.

Returning to:

if ( req.http.cookie != "") {
  return(pass);
}

That won’t be effective as planned, since both a cookie value and a null would evaluate to TRUE.

A way to check if a variable is set, while being agnostic about whether that’s empty or null could be this:

if ( req.http.cookie ~ ".") {
  return(pass);
}