The headerplus
is a vmod for advanced header access, creation and manipulation for
singular headers, multiple headers of the same name, or groups of headers through regex.
Additionally, this VMOD provides an easy to use API to access and manipulate individual
attributes from a header.
Documentation for the legacy vmod-header
can be found here.
import headerplus;
sub vcl_backend_response {
headerplus.init(beresp);
set bereq.http.stale-if-error = headerplus.attr_get("Cache-Control", "stale-if-error");
if (bereq.http.stale-if-error != "") {
set beresp.keep = std.duration(bereq.http.stale-if-error + "s", 11s);
}
}
import headerplus;
sub vcl_recv {
headerplus.init(req);
headerplus.delete_regex("^X-");
headerplus.write();
}
import headerplus;
import ykey;
sub vcl_backend_response {
headerplus.init(beresp);
headerplus.collapse_regex("^ykey-", "all-ykey");
headerplus.write();
ykey.add_key(beresp.http.all-key);
}
import headerplus;
sub vcl_recv {
headerplus.init(req);
headerplus.keep("Host");
headerplus.keep("X-Forwarded-For");
headerplus.keep("Connection");
headerplus.keep("Accept-Language");
headerplus.keep("Accept-Encoding");
headerplus.keep("Referer");
headerplus.keep("User-Agent");
headerplus.keep("Authorization");
headerplus.keep("Cookie");
headerplus.keep_regex("^Upgrade-.*");
headerplus.keep_regex("^Sec-.*");
headerplus.write();
}
init()
is required to be called before using any other function. All functions keep an
internal state of the URL until it is written out using write()
.
This VMOD uses a state called keep
mode, enabled by calling keep()
or keep_regex()
.
When keep()
or keep_regex()
is called, all headers except those matching the specified
name are implicitly marked for deletion. This means that headers will be deleted when write()
occurs unless they are explicitly kept by subsequent keep()
or keep_regex()
calls.
For example, if you have the following headers: Host, User-Agent, Accept-Encoding, and Cookie,
and then you set keep("Host");
, the User-Agent, Accept-Encoding, and Cookie headers will be
marked for deletion even if you do not call the delete()
function. Simply put, in general,
if at least one header is set in keep()
, the rest of the headers will be unset.
You can call keep()
or keep_regex()
multiple times to retain multiple headers. Similarly,
the keep
parameter in some functions, such as add()
and set()
, marks headers to be kept,
which can be referenced by filtering functions such as delete(). For example, all headers without
a keep flag can be marked for deletion.
The delete()
and delete_regex()
functions operate in the opposite way of keep()
and
keep_regex()
. If there is at least one header in the delete()
function, then that header
alone will be deleted. This contrasts with keep()
, where setting at least one header to be
kept will mark the rest of the headers for deletion. For example, if you have the following
headers: Host, User-Agent, Accept-Encoding, and Cookie, and then you set delete("Host");
, only
the Host header will be unset.
When a header name is marked for both retention and deletion, the header is kept. A regular expression that is not specific enough is a common cause of double marking, and care must be taken to prevent ambiguous marking.
All parameters that use regex (noted by a _re
suffix) must be a static string and cannot
change between requests. Regex on header names (noted by name_re
) are case insensitive.
VOID init(HTTP scope)
Set up the internal state of headers. This is required to be called before any of the below functions can be used.
Arguments:
scope
accepts type HTTPType: Function
Returns: None
VOID init_req()
A variant of init
that targets the appropriate scope between req
or
bereq
depending on where it is called. This can be useful for code reuse
across contexts
sub myapp_cleanup {
headerplus.init_req();
headerplus.delete_regex("^myapp-");
headerplus.write();
}
sub vcl_recv {
# prevent myapp-* headers injection in req
call myapp_cleanup;
# internally use myapp-* headers
}
sub vcl_backend_fetch {
# don't forward internal headers with bereq
call myapp_cleanup;
}
This function must be called from a context where either req
or bereq
is writable.
Arguments: None
Type: Function
Returns: None
Restricted to: client
, backend
VOID init_resp()
The counterpart of init_req
for respectively resp
or beresp
.
Arguments: None
Type: Function
Returns: None
Restricted to: client
, backend
VOID reset()
Clear the internal state of headers.
Arguments: None
Type: Function
Returns: None
VOID reset_req()
Roll back any modification to req
or bereq
depending on where this
function is called. All changes, whether performed by this VMOD or not, are
reverted to the initial request, including across restarts and retries.
It is conceptually equivalent to executing the following operations atomically:
headerplus.init_req();
for each header not present in the initial request
headerplus.delete(<name>);
for each header present in the initial request
headerplus.set(<name>, <value>);
headerplus.write();
The rollback is comprehensive and includes the following pseudo-headers:
req.method
req.url
req.proto
(not to be modified anyway, read-only since VCL 4.1)Arguments: None
Type: Function
Returns: None
Restricted to: client
, backend
VOID write()
Write out the internal state of headers to the scope.
Arguments: None
Type: Function
Returns: None
VOID write_req0()
This function is experimental. This means that its name and functionality is subject to change until this notice has been removed. In other words, use it with care, test well, and report any problems which might occur.
This function is only available in sub vcl_recv
, and is
designed to be used in conjunction with return (vcl(label));
. It is also only available in the top request, not
ESI or slicer sub requests.
This function is very similar to write
, but it does not update
the req.*
variables. Instead, it updates the internal structure
representing the original request (hence req0
).
This internal structure is the starting point of request handling, for the main VCL, for label VCLs and for ESI and slicer sub requests.
This means that when the function returns, calling
return(vcl(label))
will make the state or req.*
“reset”
to the new starting point (and not the original starting point,
which is normally the case), and VCL processing will start again
in the label. In a similar way, ESI and slicer sub requests will
also start at this new starting point.
Note that even though req.url
and req.method
need to be
set outside of the headerplus
VMOD, they will be copied over
to req0 through write_req0()
.
Calling std.rollback()
will similarly reset to the new req0
.
Arguments: None
Type: Function
Returns: None
Restricted to: vcl_recv
VOID add(STRING name, STRING value, BOOL keep = 1)
Add a new header. This function does not overwrite or remove headers of the same name.
The parameter keep
is described in the API section.
Arguments:
name
accepts type STRING
value
accepts type STRING
keep
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID set(STRING name, STRING value, BOOL keep = 1)
Set a new header. Removes all previous headers of the same name.
The parameter keep
is described in the API section.
Arguments:
name
accepts type STRING
value
accepts type STRING
keep
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID append(STRING name, STRING value, STRING delim = ", ", BOOL all = 0, BOOL keep = 1)
Append a value to the end of a header. If all
is true
, append to all
headers of same name. The keep
value is inherited from the original header.
If the header is not present, create a new one using keep
as the keep value.
The parameter keep
is described in the API section.
Arguments:
name
accepts type STRING
value
accepts type STRING
delim
accepts type STRING with a default value of ,
optional
all
accepts type BOOL with a default value of 0
optional
keep
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
STRING get(STRING name, [STRING value_re], STRING def = 0)
Return the value of the first header matching name
. If value_re
is
present, the value must match as well.
Arguments:
name
accepts type STRING
def
accepts type STRING with a default value of 0
optional
value_re
accepts type STRING
Type: Function
Returns: String
STRING get_regex(STRING name_re, [STRING value_re], STRING def = 0)
Return the value of the first header matching name_re
. If value
is
present, the value_re
must match as well.
Arguments:
name_re
accepts type STRING
def
accepts type STRING with a default value of 0
optional
value_re
accepts type STRING
Type: Function
Returns: String
STRING get_name_regex([STRING name_re], [STRING value_re])
Return the name of the first header matching name_re
. If value_re
is
present, the value must match as well. If name_re
is not present,
return the name of the first header with a value matching ``value_re.
If neither are present, return the first header.
Arguments:
name_re
accepts type STRING
value_re
accepts type STRING
Type: Function
Returns: String
STRING collapse(STRING name, [STRING new_name], STRING delim = ", ", BOOL keep = 1)
Merge all headers with name
. Optionally rename the header to new_name
.
The parameter keep
is described in the API section.
Arguments:
name
accepts type STRING
delim
accepts type STRING with a default value of ,
optional
keep
accepts type BOOL with a default value of 1
optional
new_name
accepts type STRING
Type: Function
Returns: String
STRING collapse_regex(STRING name_re, STRING new_name, STRING delim = ", ", BOOL keep = 1)
Merge all headers matching name_re
to a new header new_name
.
Overwrites headers matching name_re
.
The parameter keep
is described in the API section.
Arguments:
name_re
accepts type STRING
new_name
accepts type STRING
delim
accepts type STRING with a default value of ,
optional
keep
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: String
VOID split(STRING name, STRING delim = ", ")
Split header name
into multiple headers, breaking up the value by delim.
Overwrites header name
. The keep
value is inherited from the original header.
Arguments:
name
accepts type STRING
delim
accepts type STRING with a default value of ,
optional
Type: Function
Returns: None
INT count(STRING name)
Return the number of headers with name
.
Arguments:
name
accepts type STRINGType: Function
Returns: Int
INT count_regex(STRING name_re)
Return the number of headers matching name_re
.
Arguments:
name_re
accepts type STRINGType: Function
Returns: Int
VOID keep(STRING name)
Enable keep mode and keep all headers with name
.
Arguments:
name
accepts type STRINGType: Function
Returns: None
VOID keep_regex(STRING name_re)
Enable keep mode and keep all headers with names matching name_re
.
Arguments:
name_re
accepts type STRINGType: Function
Returns: None
VOID delete(STRING name, BOOL delete_keep = 0)
Remove all headers with name
. If set to true
, delete kept headers.
Arguments:
name
accepts type STRING
delete_keep
accepts type BOOL with a default value of 0
optional
Type: Function
Returns: None
VOID delete_regex(STRING name_re, BOOL delete_keep = 0)
Remove all headers matching name_re
. If set to true
, delete kept headers.
Arguments:
name_re
accepts type STRING
delete_keep
accepts type BOOL with a default value of 0
optional
Type: Function
Returns: None
VOID rename(STRING name, STRING new_name, BOOL remove = 1)
Change the name of all headers matching name
to new_name
.
Remove original header when remove
is true
, otherwise a new header is
appended.
Arguments:
name
accepts type STRING
new_name
accepts type STRING
remove
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID regsub_name(STRING name_re, STRING sub, BOOL all = 0, BOOL remove = 1)
Regsub on all headers matching name_re
. Rename headers matching
name_re
. sub
is the substitution pattern. The regex can be repeated on
the name if all
is true
. Remove original header when remove
is true
,
otherwise a new header is added.
Arguments:
name_re
accepts type STRING
sub
accepts type STRING
all
accepts type BOOL with a default value of 0
optional
remove
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID regsub_value(STRING name_re, STRING value_re, STRING sub, BOOL all = 0)
Regsub the value on all headers matching name_re
. sub
is the substitution
pattern. The regex can be repeated on the value if all
is true
.
Arguments:
name_re
accepts type STRING
value_re
accepts type STRING
sub
accepts type STRING
all
accepts type BOOL with a default value of 0
optional
Type: Function
Returns: None
VOID prefix(STRING name_re, STRING prefix, BOOL remove = 1)
Add a prefix to all headers matching name_re
. Overwrites headers matching
name_re
. name_re
is grouped. Remove original header when remove
is
true
, otherwise a new header is added.
Arguments:
name_re
accepts type STRING
prefix
accepts type STRING
remove
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID suffix(STRING name_re, STRING suffix, BOOL remove = 1)
Add a suffix to all headers matching name_re
. Overwrites headers matching
name_re
. name_re
is grouped. Remove original header when remove
is true
, otherwise a new header is added.
Arguments:
name_re
accepts type STRING
suffix
accepts type STRING
remove
accepts type BOOL with a default value of 1
optional
Type: Function
Returns: None
VOID from_json(STRING json, BOOL overwrite = 0, BOOL keep = 1, BOOL skip = 0)
Add the values of a JSON string as headers. The format should be
{"header": "value"}
. To add multiple headers an array should be used.
For example, {"X-ample": ["a", "b", "c"]}
will result in 3 headers with
a name of X-ample
with the values of a
, b
, and c
. If overwrite
is
true
, overwrite headers from the current scope. Multiple headers with the
same name in json
will not be overwritten.
skip
being true
only set headers that don’t already have at least
one value in the internal state. Setting both skip
and `overwrite`` will
trigger a VCL failure.
The parameter keep
is described in the API section.
Arguments:
json
accepts type STRING
overwrite
accepts type BOOL with a default value of 0
optional
keep
accepts type BOOL with a default value of 1
optional
skip
accepts type BOOL with a default value of 0
optional
Type: Function
Returns: None
STRING as_list(ENUM {BOTH, NAME, VALUE} which = "BOTH", STRING hdr_delim = ", ", STRING value_delim = ": ", BOOL sort = 1, ENUM {NONE, UPPER, LOWER} name_case = NONE)
Turn the set of headers to a string. This can be made up of just header names, just header values, or both headers and values.
Arguments:
hdr_delim
accepts type STRING with a default value of ,
optional
value_delim
accepts type STRING with a default value of :
optional
sort
accepts type BOOL with a default value of 1
optional
which
is an ENUM that accepts values of BOTH
, NAME
, and VALUE
with a default value of BOTH
optional
name_case
is an ENUM that accepts values of NONE
, UPPER
, and LOWER
with a default value of NONE
optional
Type: Function
Returns: String
STRING as_json(ENUM {FIRST, LAST, ARRAY, ALL} which = FIRST)
Turn set of headers to a JSON string in the format of {"header":"value"}
.
which
dictates which header to use if there are multiple headers. Use either
the first header, last header, combine them into an array, or add all headers
as is.
Arguments:
which
is an ENUM that accepts values of FIRST
, LAST
, ARRAY
, and ALL
with a default value of FIRST
optional
Type: Function
Returns: String
STRING attr_get(STRING name, STRING attr, STRING hdr_delim = ", ", STRING attr_delim = " = ", STRING def = 0)
Return the value of the attribute of a header name
. For example, if header
Cache-Control: public, max-age=123
is present, given name
Cache-Control
and attr
max-age, 123 is returned. The first instance of attr
is returned.
Arguments:
name
accepts type STRING
attr
accepts type STRING
hdr_delim
accepts type STRING with a default value of ,
optional
attr_delim
accepts type STRING with a default value of =
optional
def
accepts type STRING with a default value of 0
optional
Type: Function
Returns: String
BOOL attr_exists(STRING name, STRING attr, STRING hdr_delim = ", ", STRING attr_delim = " = ")
Returns true if the attribute of a header name
exists.
Arguments:
name
accepts type STRING
attr
accepts type STRING
hdr_delim
accepts type STRING with a default value of ,
optional
attr_delim
accepts type STRING with a default value of =
optional
Type: Function
Returns: Bool
VOID attr_set(STRING name, STRING attr, STRING value = "", STRING hdr_delim = ", ", STRING attr_delim = " = ", ENUM {FIRST, UPDATE, ALL} how = FIRST)
Set the value of the attribute of a header name
. For example, if header
Cache-Control: public, max-age=123
is present, given name
Cache-Control
and attr
max-age, max-age will be set to value
. If how
is UPDATE
,
the attribute will be added to all matching headers containing the
attribute and attribute deliminator. If how
is FIRST
update the
attribute to the first matching headers containing the attribute and
attribute deliminator. If it is not found, append to the first header matching
name. If how
is ALL
the value will be updated or appended to all headers
matching name
.
Arguments:
name
accepts type STRING
attr
accepts type STRING
value
accepts type STRING with a default value of empty. optional
hdr_delim
accepts type STRING with a default value of ,
optional
attr_delim
accepts type STRING with a default value of =
optional
how
is an ENUM that accepts values of FIRST
, UPDATE
, and ALL
with a default value of FIRST
optional
Type: Function
Returns: None
VOID attr_delete(STRING name, STRING attr, STRING hdr_delim = ", ", BOOL all = 0, STRING attr_delim = " = ")
Remove the attribute of a header name
. For example, if header
Cache-Control: public, max-age=123
is present given name
Cache-Control
and attr
max-age, max-age=123
will be removed from the header. If the
header is empty after removing attr
the header will be deleted. If all
is true
, the value is removed from all headers matching name
. The first
instance of attr
is removed. hdr_delim
is a list of header delimiters.
Arguments:
name
accepts type STRING
attr
accepts type STRING
hdr_delim
accepts type STRING with a default value of ,
optional
all
accepts type BOOL with a default value of 0
optional
attr_delim
accepts type STRING with a default value of =
optional
Type: Function
Returns: None
INT attr_count(STRING name, STRING hdr_delim = ", ", STRING attr_delim = " = ")
Return the number of attributes of a header name
.
Arguments:
name
accepts type STRING
hdr_delim
accepts type STRING with a default value of ,
optional
attr_delim
accepts type STRING with a default value of =
optional
Type: Function
Returns: Int
The headerplus
VMOD is available in Varnish Enterprise version 6.0.6r6
and later.