MINOR: vars: make the vars() sample fetch function support a default value

It is quite common to see in configurations constructions like the
following one:

    http-request set-var(txn.bodylen) 0
    http-request set-var(txn.bodylen) req.hdr(content-length)
    ...
    http-request set-header orig-len %[var(txn.bodylen)]

The set-var() rules are almost always duplicated when manipulating
integers or any other value that is mandatory along operations. This is
a problem because it makes the configurations complicated to maintain
and slower than needed. And it becomes even more complicated when several
conditions may set the same variable because the risk of forgetting to
initialize it or to accidentally reset it is high.

This patch extends the var() sample fetch function to take an optional
argument which contains a default value to be returned if the variable
was not set. This way it becomes much simpler to use the variable, just
set it where needed, and read it with a fall back to the default value:

    http-request set-var(txn.bodylen) req.hdr(content-length)
    ...
    http-request set-header orig-len %[var(txn.bodylen,0)]

The default value is always passed as a string, thus it will experience
a cast to the output type. It doesn't seem userful to complicate the
configuration to pass an explicit type at this point.

The vars.vtc regtest was updated accordingly.
This commit is contained in:
Willy Tarreau 2021-09-03 12:00:13 +02:00
parent e352b9dac7
commit 54496a6a5b
3 changed files with 12 additions and 6 deletions

View File

@ -17764,10 +17764,11 @@ uuid([<version>]) : string
specified, a UUID version 4 (fully random) is returned.
Currently, only version 4 is supported.
var(<var-name>) : undefined
var(<var-name>[,<default>]) : undefined
Returns a variable with the stored type. If the variable is not set, the
sample fetch fails. The name of the variable starts with an indication
about its scope. The scopes allowed are:
sample fetch fails, unless a default value is provided, in which case it will
return it as a string. Empty strings are permitted. The name of the variable
starts with an indication about its scope. The scopes allowed are:
"proc" : the variable is shared with the whole process
"sess" : the variable is shared with the whole session
"txn" : the variable is shared with the transaction (request and

View File

@ -5,8 +5,9 @@ feature ignore_unknown_macro
haproxy h1 -conf {
global
# note below, str60 is purposely not defined so that the default is used
set-var proc.int12 int(12)
set-var proc.int5 str(60),div(proc.int12)
set-var proc.int5 var(proc.str60,60),div(proc.int12)
set-var proc.str1 str("this is")
set-var proc.str2 str("a string")
set-var proc.str var(proc.str1)

View File

@ -339,8 +339,12 @@ static inline struct var *var_get(struct vars *vars, const char *name)
static int smp_fetch_var(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
const struct var_desc *var_desc = &args[0].data.var;
const struct buffer *def = NULL;
return vars_get_by_desc(var_desc, smp, NULL);
if (args[1].type == ARGT_STR)
def = &args[1].data.str;
return vars_get_by_desc(var_desc, smp, def);
}
/* This function search in the <head> a variable with the same
@ -1193,7 +1197,7 @@ REGISTER_POST_DEINIT(vars_deinit);
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_CONST },
{ "var", smp_fetch_var, ARG2(1,STR,STR), smp_check_var, SMP_T_STR, SMP_USE_CONST },
{ /* END */ },
}};