MINOR: sample: add a new "concat" converter

It's always a pain not to be able to combine variables. This commit
introduces the "concat" converter, which appends a delimiter, a variable's
contents and another delimiter to an existing string. The result is a string.
This makes it easier to build composite variables made of other variables.
This commit is contained in:
Willy Tarreau 2018-02-19 15:34:12 +01:00
parent 16f45c87d5
commit 280f42b99e
2 changed files with 102 additions and 0 deletions

View File

@ -12810,6 +12810,27 @@ bytes(<offset>[,<length>])
sample starting at an offset (in bytes) of the original sample and sample starting at an offset (in bytes) of the original sample and
optionally truncated at the given length. optionally truncated at the given length.
concat([<start>],[<var>],[<end>])
Concatenates up to 3 fields after the current sample which is then turned to
a string. The first one, <start>, is a constant string, that will be appended
immediately after the existing sample. It may be omitted if not used. The
second one, <var>, is a variable name. The variable will be looked up, its
contents converted to a string, and it will be appended immediately after the
<first> part. If the variable is not found, nothing is appended. It may be
omitted as well. The third field, <end> is a constant string that will be
appended after the variable. It may also be omitted. Together, these elements
allow to concatenate variables with delimiters to an existing set of
variables. This can be used to build new variables made of a succession of
other variables, such as colon-delimited varlues. Note that due to the config
parser, it is not possible to use a comma nor a closing parenthesis as
delimitors.
Example:
tcp-request session set-var(sess.src) src
tcp-request session set-var(sess.dn) ssl_c_s_dn
tcp-request session set-var(txn.sig) str(),concat(<ip=,sess.ip,>),concat(<dn=,sess.dn,>)
http-request set-header x-hap-sig %[var(txn.sig)]
cpl cpl
Takes the input value of type signed integer, applies a ones-complement Takes the input value of type signed integer, applies a ones-complement
(flips all bits) and returns the result as an signed integer. (flips all bits) and returns the result as an signed integer.

View File

@ -2531,6 +2531,83 @@ static int sample_conv_arith_even(const struct arg *arg_p,
return 1; return 1;
} }
/* appends an optional const string, an optional variable contents and another
* optional const string to an existing string.
*/
static int sample_conv_concat(const struct arg *arg_p, struct sample *smp, void *private)
{
struct chunk *trash;
struct sample tmp;
int max;
trash = get_trash_chunk();
trash->len = smp->data.u.str.len;
if (trash->len > trash->size - 1)
trash->len = trash->size - 1;
memcpy(trash->str, smp->data.u.str.str, trash->len);
trash->str[trash->len] = 0;
/* append first string */
max = arg_p[0].data.str.len;
if (max > trash->size - 1 - trash->len)
max = trash->size - 1 - trash->len;
if (max) {
memcpy(trash->str + trash->len, arg_p[0].data.str.str, max);
trash->len += max;
trash->str[trash->len] = 0;
}
/* append second string (variable) if it's found and we can turn it
* into a string.
*/
smp_set_owner(&tmp, smp->px, smp->sess, smp->strm, smp->opt);
if (arg_p[1].type == ARGT_VAR && vars_get_by_desc(&arg_p[1].data.var, &tmp) &&
(sample_casts[tmp.data.type][SMP_T_STR] == c_none ||
sample_casts[tmp.data.type][SMP_T_STR](&tmp))) {
max = tmp.data.u.str.len;
if (max > trash->size - 1 - trash->len)
max = trash->size - 1 - trash->len;
if (max) {
memcpy(trash->str + trash->len, tmp.data.u.str.str, max);
trash->len += max;
trash->str[trash->len] = 0;
}
}
/* append third string */
max = arg_p[2].data.str.len;
if (max > trash->size - 1 - trash->len)
max = trash->size - 1 - trash->len;
if (max) {
memcpy(trash->str + trash->len, arg_p[2].data.str.str, max);
trash->len += max;
trash->str[trash->len] = 0;
}
smp->data.u.str = *trash;
smp->data.type = SMP_T_STR;
return 1;
}
/* This function checks the "concat" converter's arguments and extracts the
* variable name and its scope.
*/
static int smp_check_concat(struct arg *args, struct sample_conv *conv,
const char *file, int line, char **err)
{
/* Try to decode a variable. */
if (args[1].data.str.len > 0 && !vars_check_arg(&args[1], NULL)) {
memprintf(err, "failed to register variable name '%s'", args[1].data.str.str);
return 0;
}
return 1;
}
/************************************************************************/ /************************************************************************/
/* All supported sample fetch functions must be declared here */ /* All supported sample fetch functions must be declared here */
/************************************************************************/ /************************************************************************/
@ -2539,6 +2616,9 @@ static int sample_conv_arith_even(const struct arg *arg_p,
static int static int
smp_fetch_true(const struct arg *args, struct sample *smp, const char *kw, void *private) smp_fetch_true(const struct arg *args, struct sample *smp, const char *kw, void *private)
{ {
if (!smp_make_rw(smp))
return 0;
smp->data.type = SMP_T_BOOL; smp->data.type = SMP_T_BOOL;
smp->data.u.sint = 1; smp->data.u.sint = 1;
return 1; return 1;
@ -2841,6 +2921,7 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "word", sample_conv_word, ARG2(2,SINT,STR), sample_conv_field_check, SMP_T_STR, SMP_T_STR }, { "word", sample_conv_word, ARG2(2,SINT,STR), sample_conv_field_check, SMP_T_STR, SMP_T_STR },
{ "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR }, { "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR },
{ "sha1", sample_conv_sha1, 0, NULL, SMP_T_BIN, SMP_T_BIN }, { "sha1", sample_conv_sha1, 0, NULL, SMP_T_BIN, SMP_T_BIN },
{ "concat", sample_conv_concat, ARG3(1,STR,STR,STR), smp_check_concat, SMP_T_STR, SMP_T_STR },
{ "and", sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, { "and", sample_conv_binary_and, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },
{ "or", sample_conv_binary_or, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, { "or", sample_conv_binary_or, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT },