MINOR: vars: Delay variable content freeing in var_set function

When calling var_set on a variable of type string (SMP_T_STR, SMP_T_BIN
or SMP_T_METH), the contents of the variable were freed directly. When
adding conditions to set-var calls we might have cases in which the
contents of an existing variable should be kept unchanged so the freeing
of the internal buffers is delayed in the var_set function (so that we
can bypass it later).
This commit is contained in:
Remi Tricot-Le Breton 2021-12-16 17:14:36 +01:00 committed by Willy Tarreau
parent 1bd9805085
commit 25fccd52ac

View File

@ -301,6 +301,25 @@ static int smp_fetch_var(const struct arg *args, struct sample *smp, const char
return vars_get_by_desc(var_desc, smp, def); return vars_get_by_desc(var_desc, smp, def);
} }
/*
* Clear the contents of a variable so that it can be reset directly.
* This function is used just before a variable is filled out of a sample's
* content.
*/
static inline void var_clear_buffer(struct sample *smp, struct vars *vars, struct var *var, int var_type)
{
if (var_type == SMP_T_STR || var_type == SMP_T_BIN) {
ha_free(&var->data.u.str.area);
var_accounting_diff(vars, smp->sess, smp->strm,
-var->data.u.str.data);
}
else if (var_type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
ha_free(&var->data.u.meth.str.area);
var_accounting_diff(vars, smp->sess, smp->strm,
-var->data.u.meth.str.data);
}
}
/* This function tries to create a variable whose name hash is <name_hash> in /* This function tries to create a variable whose name hash is <name_hash> in
* scope <scope> and store sample <smp> as its value. * scope <scope> and store sample <smp> as its value.
* *
@ -321,6 +340,7 @@ static int var_set(uint64_t name_hash, enum vars_scope scope, struct sample *smp
struct vars *vars; struct vars *vars;
struct var *var; struct var *var;
int ret = 0; int ret = 0;
int previous_type = SMP_T_ANY;
vars = get_vars(smp->sess, smp->strm, scope); vars = get_vars(smp->sess, smp->strm, scope);
if (!vars || vars->scope != scope) if (!vars || vars->scope != scope)
@ -336,19 +356,6 @@ static int var_set(uint64_t name_hash, enum vars_scope scope, struct sample *smp
ret = 1; ret = 1;
goto unlock; goto unlock;
} }
/* free its used memory. */
if (var->data.type == SMP_T_STR ||
var->data.type == SMP_T_BIN) {
ha_free(&var->data.u.str.area);
var_accounting_diff(vars, smp->sess, smp->strm,
-var->data.u.str.data);
}
else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
ha_free(&var->data.u.meth.str.area);
var_accounting_diff(vars, smp->sess, smp->strm,
-var->data.u.meth.str.data);
}
} else { } else {
if (flags & VF_UPDATEONLY) if (flags & VF_UPDATEONLY)
goto unlock; goto unlock;
@ -368,22 +375,27 @@ static int var_set(uint64_t name_hash, enum vars_scope scope, struct sample *smp
} }
/* Set type. */ /* Set type. */
previous_type = var->data.type;
var->data.type = smp->data.type; var->data.type = smp->data.type;
/* Copy data. If the data needs memory, the function can fail. */ /* Copy data. If the data needs memory, the function can fail. */
switch (var->data.type) { switch (var->data.type) {
case SMP_T_BOOL: case SMP_T_BOOL:
case SMP_T_SINT: case SMP_T_SINT:
var_clear_buffer(smp, vars, var, previous_type);
var->data.u.sint = smp->data.u.sint; var->data.u.sint = smp->data.u.sint;
break; break;
case SMP_T_IPV4: case SMP_T_IPV4:
var_clear_buffer(smp, vars, var, previous_type);
var->data.u.ipv4 = smp->data.u.ipv4; var->data.u.ipv4 = smp->data.u.ipv4;
break; break;
case SMP_T_IPV6: case SMP_T_IPV6:
var_clear_buffer(smp, vars, var, previous_type);
var->data.u.ipv6 = smp->data.u.ipv6; var->data.u.ipv6 = smp->data.u.ipv6;
break; break;
case SMP_T_STR: case SMP_T_STR:
case SMP_T_BIN: case SMP_T_BIN:
var_clear_buffer(smp, vars, var, previous_type);
if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) { if (!var_accounting_add(vars, smp->sess, smp->strm, smp->data.u.str.data)) {
var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */ var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
goto unlock; goto unlock;
@ -401,6 +413,7 @@ static int var_set(uint64_t name_hash, enum vars_scope scope, struct sample *smp
var->data.u.str.data); var->data.u.str.data);
break; break;
case SMP_T_METH: case SMP_T_METH:
var_clear_buffer(smp, vars, var, previous_type);
var->data.u.meth.meth = smp->data.u.meth.meth; var->data.u.meth.meth = smp->data.u.meth.meth;
if (smp->data.u.meth.meth != HTTP_METH_OTHER) if (smp->data.u.meth.meth != HTTP_METH_OTHER)
break; break;