vmod_header(3)

πŸ’– vmod_header β€” the Header VMOD for Varnish πŸ’–

okay so bestie, you've landed in vmod_header(3), a page from the Library Functions Manual, and honestly? it's giving "i need to juggle a million duplicate HTTP headers and not lose my mind" energy. and it ate. let's get into it 🫢


✨ SYNOPSIS ✨

import header [as name] [from "path"]

VOID append(HEADER, STRING)

VOID copy(HEADER, HEADER)

STRING get(HEADER header, REGEX regex)

VOID remove(HEADER header, REGEX regex)

VOID regsub(HTTP, REGEX regex, STRING sub, BOOL all)

HEADER dyn(HTTP, STRING)

no cap, that's the whole toolkit right there πŸ‘‘


πŸ¦‹ DESCRIPTION πŸ¦‹

so basically this is the Varnish Module for manipulation of duplicated HTTP headers, for instance multiple Set-Cookie headers. you know the vibe β€” same header name, many lines, and you gotta be the main character who keeps them all in line πŸ’…

Example:

vcl 4.0;
import header;

backend default { .host = "192.0.2.11"; .port = "8080"; }

sub vcl_backend_response {
    if (beresp.http.Set-Cookie) {
        # Add another line of Set-Cookie in the response.
        header.append(beresp.http.Set-Cookie, "VSESS=abbabeef");

        # CMS always set this, but doesn't really need it.
        header.remove(beresp.http.Set-Cookie, "JSESSIONID=");
    }
}

look at that. two lines of Set-Cookie, one added, one scrubbed. lowkey iconic πŸ”₯


🌸 VOID append(HEADER, STRING) 🌸

Description

Append an extra occurrence to an existing header. yes, just... one more. the header is collecting them like stickers ✨

Example

:: header.append(beresp.http.Set-Cookie, "foo=bar")

πŸŽ€ VOID copy(HEADER, HEADER) πŸŽ€

Description

Copy all source headers to a new header. it's giving "i'm duplicating this whole situation for reasons that are mine alone" πŸ’…

Example

:: header.copy(beresp.http.set-cookie, beresp.http.x-old-cookie);

🌈 STRING get(HEADER header, REGEX regex) 🌈

Description

Fetches the value of the first header that matches the given regular expression regex. first match only, bestie β€” it's not gonna scroll for more πŸ™ˆ

Example

:: set beresp.http.xusr =
header.get(beresp.http.set-cookie,"user=");

πŸ’œ VOID remove(HEADER header, REGEX regex) πŸ’œ

Description

Remove all occurrences of header that matches regex. ALL of them. no survivors, periodt πŸ’€

Example

:: header.remove(beresp.http.set-cookie,"^(?!(funcookie=))");

⭐ VOID regsub(HTTP, REGEX regex, STRING sub, BOOL all=0) ⭐

Description

For every header line in the HTTP object β€” which can be one of req, resp, bereq or beresp β€” if the line matches the regular expression regex, then replace it with the result of a substitution using the string sub. sub may include backreferences of the form \1 through \9, which refer to capturing expressions in the regex, or \0 to refer to the entire matched portion of the header line. yes girl, backreferences, we love a callback πŸ‘‘

If all is false, replace the first matched portion of the header line with sub. This is the same operation performed by the VCL native function regsub(). all is false by default.

If all is true, replace each non-overlapping matched portion of the header line with sub. This is the same operation performed by native regsuball().

⚠️ okay important one: note that unlike the other functions in this VMOD, regsub() applies to the entire header line, including the header name, colon separator, and header value. take care that your substitutions result in valid headers, since ill-formed headers can interfere with the HTTP protocol. this is the part where you slow down and double-check, fr fr 😭

Consider case sensitivity in the regex match. The standard dictates that header names are case insensitive, but header values are not. The VMOD function does not take care of that for you, but you can express it in the regex using the (?i) flag, as shown in the example below (use (?-i) to turn it off).

Consider using the ^ starting anchor in regex to be sure to match a header name (and not the same string somewhere in the middle of the line).

Example

:: header.regsub(req, "^(?i)Foo(\d): (?-i)bar=(.*)$", "Bar\1:
\2")

🧚 HEADER dyn(HTTP, STRING) 🧚

Description

Return a dynamic header name.

Most other functions of this vmod require a HEADER argument, which usually is a VCL-defined header like req.http.foo.

This function allows to construct a header name from an arbitrary string, which may also be dynamically created, for example from a variable. main character energy: you build the name yourself 🌟

πŸ™ˆ Notice that there are no syntactic checks on the STRING argument by purpose in order to support exotic use cases. It is entirely up to the user and at their own risk to supply a string which represents a valid HTTP header name (or not). so like... you're on your own here, bestie. no seatbelt. no cap.

Example

:: # create this request header # 42: is the answer
header.append(header.dyn(req, 35 + 7), "is the answer");

🌷 ACKNOWLEDGEMENTS 🌷

The development of this plugin was made possible by the sponsorship of Softonic, <http://en.softonic.com/> .

Also thanks to Imo Klabun and Anders Nordby for bug reports. we stan a bug reporter 🫢


πŸ’€ BUGS πŸ’€

You can't use dynamic regular expressions, which also holds true for normal regular expressions in regsub(). that's just the rules, sorry babe 😭


and that's the whole page, bestie!! this was vmod_header(3) from the Library Functions Manual β€” the vmod_header(3) of it all, you know? anyway, stay slaying those duplicate headers, and remember: valid headers only, or the HTTP protocol WILL side-eye you πŸ’…βœ¨πŸ¦‹