diff --git a/doc/configuration.txt b/doc/configuration.txt index 1ae983476..e14f4666e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -11031,11 +11031,29 @@ The currently available list of transformation keywords include : add() Adds to the input value of type signed integer, and returns the - result as a signed integer. + result as a signed integer. can be a numeric value or a variable + name. The name of the variable starts by an indication about its scope. The + allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. and() Performs a bitwise "AND" between and the input value of type signed - integer, and returns the result as an signed integer. + integer, and returns the result as an signed integer. can be a + numeric value or a variable name. The name of the variable starts by an + indication about its scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. base64 Converts a binary input sample to a base64 string. It is used to log or @@ -11092,7 +11110,16 @@ debug div() Divides the input value of type signed integer by , and returns the result as an signed integer. If is null, the largest unsigned - integer is returned (typically 2^63-1). + integer is returned (typically 2^63-1). can be a numeric value or a + variable name. The name of the variable starts by an indication about it + scope. The scope allowed are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. djb2([]) Hashes a binary input sample into an unsigned 32-bit quantity using the DJB2 @@ -11287,11 +11314,29 @@ map__([,]) mod() Divides the input value of type signed integer by , and returns the remainder as an signed integer. If is null, then zero is returned. + can be a numeric value or a variable name. The name of the variable + starts by an indication about its scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. mul() Multiplies the input value of type signed integer by , and returns the product as an signed integer. In case of overflow, the largest possible value for the sign is returned so that the operation doesn't wrap around. + can be a numeric value or a variable name. The name of the variable + starts by an indication about its scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. neg Takes the input value of type signed integer, computes the opposite value, @@ -11311,7 +11356,16 @@ odd or() Performs a bitwise "OR" between and the input value of type signed - integer, and returns the result as an signed integer. + integer, and returns the result as an signed integer. can be a + numeric value or a variable name. The name of the variable starts by an + indication about its scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. regsub(,[,]) Applies a regex-based substitution to the input string. It does the same @@ -11377,7 +11431,16 @@ set-var() sub() Subtracts from the input value of type signed integer, and returns the result as an signed integer. Note: in order to subtract the input from - a constant, simply perform a "neg,add(value)". + a constant, simply perform a "neg,add(value)". can be a numeric value + or a variable name. The name of the variable starts by an indication about its + scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. table_bytes_in_rate() Uses the string representation of the input sample to perform a look up in @@ -11559,6 +11622,15 @@ wt6([]) xor() Performs a bitwise "XOR" (exclusive OR) between and the input value of type signed integer, and returns the result as an signed integer. + can be a numeric value or a variable name. The name of the variable + starts by an indication about its scope. The allowed scopes are: + "sess" : the variable is shared with all the session, + "txn" : the variable is shared with all the transaction (request and + response), + "req" : the variable is shared only during the request processing, + "res" : the variable is shared only during the response processing. + This prefix is followed by a name. The separator is a '.'. The name may only + contain characters 'a-z', 'A-Z', '0-9' and '_'. 7.3.2. Fetching samples from internal states diff --git a/src/sample.c b/src/sample.c index 41e754011..eb005365c 100644 --- a/src/sample.c +++ b/src/sample.c @@ -31,6 +31,7 @@ #include #include #include +#include /* sample type names */ const char *smp_to_type[SMP_TYPES] = { @@ -2017,6 +2018,58 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void return 1; } +/* This function check an operator entry. It expects a string. + * The string can be an integer or a variable name. + */ +static int check_operator(struct arg *args, struct sample_conv *conv, + const char *file, int line, char **err) +{ + const char *str; + const char *end; + + /* Try to decode a variable. */ + if (vars_check_arg(&args[0], NULL)) + return 1; + + /* Try to convert an integer */ + str = args[0].data.str.str; + end = str + strlen(str); + args[0].data.sint = read_int64(&str, end); + if (*str != '\0') { + memprintf(err, "expects an integer or a variable name"); + return 0; + } + args[0].type = ARGT_SINT; + return 1; +} + +/* This fucntion returns a sample struct filled with a arg content. + * If the arg contain an integer, the integer is returned in the + * sample. If the arg contains a variable descriptor, it returns the + * variable value. + * + * This function returns 0 if an error occurs, otherwise it returns 1. + */ +static inline int sample_conv_var2smp(const struct arg *arg, struct stream *strm, struct sample *smp) +{ + switch (arg->type) { + case ARGT_SINT: + smp->type = SMP_T_SINT; + smp->data.sint = arg->data.sint; + return 1; + case ARGT_VAR: + if (!vars_get_by_desc(&arg->data.var, strm, smp)) + return 0; + if (!sample_casts[smp->type][SMP_T_SINT]) + return 0; + if (!sample_casts[smp->type][SMP_T_SINT](smp)) + return 0; + return 1; + default: + return 0; + } +} + /* Takes a SINT on input, applies a binary twos complement and returns the SINT * result. */ @@ -2026,30 +2079,42 @@ static int sample_conv_binary_cpl(const struct arg *arg_p, struct sample *smp, v return 1; } -/* Takes a SINT on input, applies a binary "and" with the UINT in arg_p, and - * returns the SINT result. +/* Takes a SINT on input, applies a binary "and" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. */ static int sample_conv_binary_and(const struct arg *arg_p, struct sample *smp, void *private) { - smp->data.sint &= arg_p->data.sint; + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + smp->data.sint &= tmp.data.sint; return 1; } -/* Takes a SINT on input, applies a binary "or" with the UINT in arg_p, and - * returns the SINT result. +/* Takes a SINT on input, applies a binary "or" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. */ static int sample_conv_binary_or(const struct arg *arg_p, struct sample *smp, void *private) { - smp->data.sint |= arg_p->data.sint; + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + smp->data.sint |= tmp.data.sint; return 1; } -/* Takes a SINT on input, applies a binary "xor" with the UINT in arg_p, and - * returns the SINT result. +/* Takes a SINT on input, applies a binary "xor" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. */ static int sample_conv_binary_xor(const struct arg *arg_p, struct sample *smp, void *private) { - smp->data.sint ^= arg_p->data.sint; + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + smp->data.sint ^= tmp.data.sint; return 1; } @@ -2079,26 +2144,35 @@ static inline long long int arith_add(long long int a, long long int b) return a + b; } -/* Takes a SINT on input, applies an arithmetic "add" with the UINT in arg_p, - * and returns the SINT result. +/* Takes a SINT on input, applies an arithmetic "add" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. */ static int sample_conv_arith_add(const struct arg *arg_p, struct sample *smp, void *private) { - smp->data.sint = arith_add(smp->data.sint, arg_p->data.sint); + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + smp->data.sint = arith_add(smp->data.sint, tmp.data.sint); return 1; } -/* Takes a SINT on input, applies an arithmetic "sub" with the UINT in arg_p, - * and returns the SINT result. +/* Takes a SINT on input, applies an arithmetic "sub" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. */ static int sample_conv_arith_sub(const struct arg *arg_p, struct sample *smp, void *private) { + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + /* We cannot represent -LLONG_MIN because abs(LLONG_MIN) is greater * than abs(LLONG_MAX). So, the following code use LLONG_MAX in place * of -LLONG_MIN and correct the result. */ - if (arg_p->data.sint == LLONG_MIN) { + if (tmp.data.sint == LLONG_MIN) { smp->data.sint = arith_add(smp->data.sint, LLONG_MAX); if (smp->data.sint < LLONG_MAX) smp->data.sint++; @@ -2108,20 +2182,26 @@ static int sample_conv_arith_sub(const struct arg *arg_p, /* standard substraction: we use the "add" function and negate * the second operand. */ - smp->data.sint = arith_add(smp->data.sint, -arg_p->data.sint); + smp->data.sint = arith_add(smp->data.sint, -tmp.data.sint); return 1; } -/* Takes a SINT on input, applies an arithmetic "mul" with the UINT in arg_p, - * and returns the SINT result. +/* Takes a SINT on input, applies an arithmetic "mul" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. + * If the result makes an overflow, then the largest possible quantity is + * returned. */ static int sample_conv_arith_mul(const struct arg *arg_p, struct sample *smp, void *private) { + struct sample tmp; long long int c; + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + /* prevent divide by 0 during the check */ - if (!smp->data.sint || !arg_p->data.sint) { + if (!smp->data.sint || !tmp.data.sint) { smp->data.sint = 0; return 1; } @@ -2129,17 +2209,17 @@ static int sample_conv_arith_mul(const struct arg *arg_p, /* The multiply between LLONG_MIN and -1 returns a * "floting point exception". */ - if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { + if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) { smp->data.sint = LLONG_MAX; return 1; } /* execute standard multiplication. */ - c = smp->data.sint * arg_p->data.sint; + c = smp->data.sint * tmp.data.sint; /* check for overflow and makes capped multiply. */ - if (smp->data.sint != c / arg_p->data.sint) { - if ((smp->data.sint < 0) == (arg_p->data.sint < 0)) { + if (smp->data.sint != c / tmp.data.sint) { + if ((smp->data.sint < 0) == (tmp.data.sint < 0)) { smp->data.sint = LLONG_MAX; return 1; } @@ -2150,44 +2230,55 @@ static int sample_conv_arith_mul(const struct arg *arg_p, return 1; } -/* Takes a SINT on input, applies an arithmetic "div" with the SINT in arg_p, - * and returns the SINT result. If arg_p makes the result overflow, then the - * largest possible quantity is returned. +/* Takes a SINT on input, applies an arithmetic "div" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. + * If arg_p makes the result overflow, then the largest possible quantity is + * returned. */ static int sample_conv_arith_div(const struct arg *arg_p, struct sample *smp, void *private) { - if (arg_p->data.sint) { + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + + if (tmp.data.sint) { /* The divide between LLONG_MIN and -1 returns a * "floting point exception". */ - if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { + if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) { smp->data.sint = LLONG_MAX; return 1; } - smp->data.sint /= arg_p->data.sint; + smp->data.sint /= tmp.data.sint; return 1; } smp->data.sint = LLONG_MAX; return 1; } -/* Takes a SINT on input, applies an arithmetic "mod" with the SINT in arg_p, - * and returns the SINT result. If arg_p makes the result overflow, then zero - * is returned. +/* Takes a SINT on input, applies an arithmetic "mod" with the SINT directly in + * arg_p or in the varaible described in arg_p, and returns the SINT result. + * If arg_p makes the result overflow, then 0 is returned. */ static int sample_conv_arith_mod(const struct arg *arg_p, struct sample *smp, void *private) { - if (arg_p->data.sint) { + struct sample tmp; + + if (!sample_conv_var2smp(arg_p, smp->strm, &tmp)) + return 0; + + if (tmp.data.sint) { /* The divide between LLONG_MIN and -1 returns a * "floting point exception". */ - if (smp->data.sint == LLONG_MIN && arg_p->data.sint == -1) { + if (smp->data.sint == LLONG_MIN && tmp.data.sint == -1) { smp->data.sint = 0; return 1; } - smp->data.sint %= arg_p->data.sint; + smp->data.sint %= tmp.data.sint; return 1; } smp->data.sint = 0; @@ -2522,20 +2613,20 @@ 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 }, { "regsub", sample_conv_regsub, ARG3(2,REG,STR,STR), sample_conv_regsub_check, SMP_T_STR, SMP_T_STR }, - { "and", sample_conv_binary_and, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "or", sample_conv_binary_or, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "xor", sample_conv_binary_xor, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "cpl", sample_conv_binary_cpl, 0, NULL, SMP_T_SINT, SMP_T_SINT }, - { "bool", sample_conv_arith_bool, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, - { "not", sample_conv_arith_not, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, - { "odd", sample_conv_arith_odd, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, - { "even", sample_conv_arith_even, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, - { "add", sample_conv_arith_add, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "sub", sample_conv_arith_sub, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "mul", sample_conv_arith_mul, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "div", sample_conv_arith_div, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "mod", sample_conv_arith_mod, ARG1(1,SINT), NULL, SMP_T_SINT, SMP_T_SINT }, - { "neg", sample_conv_arith_neg, 0, NULL, 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 }, + { "xor", sample_conv_binary_xor, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "cpl", sample_conv_binary_cpl, 0, NULL, SMP_T_SINT, SMP_T_SINT }, + { "bool", sample_conv_arith_bool, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, + { "not", sample_conv_arith_not, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, + { "odd", sample_conv_arith_odd, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, + { "even", sample_conv_arith_even, 0, NULL, SMP_T_SINT, SMP_T_BOOL }, + { "add", sample_conv_arith_add, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "sub", sample_conv_arith_sub, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "mul", sample_conv_arith_mul, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "div", sample_conv_arith_div, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "mod", sample_conv_arith_mod, ARG1(1,STR), check_operator, SMP_T_SINT, SMP_T_SINT }, + { "neg", sample_conv_arith_neg, 0, NULL, SMP_T_SINT, SMP_T_SINT }, { NULL, NULL, 0, 0, 0 }, }};