]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: vars/sample: operators can use variables as parameter
authorThierry FOURNIER <tfournier@arpalert.org>
Tue, 7 Jul 2015 19:10:16 +0000 (21:10 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 21 Jul 2015 22:48:24 +0000 (00:48 +0200)
This patch allow the existing operators to take a variable as parameter.
This is useful to add the content of two variables. This patch modify
the behavior of operators.

doc/configuration.txt
src/sample.c

index 1ae983476bc3db57df9fe6def9ac491b082078fe..e14f4666ec7a857733fb779b6d1d3f470e4909f8 100644 (file)
@@ -11031,11 +11031,29 @@ The currently available list of transformation keywords include :
 
 add(<value>)
   Adds <value> to the input value of type signed integer, and returns the
-  result as a signed integer.
+  result as a signed integer. <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 '_'.
 
 and(<value>)
   Performs a bitwise "AND" between <value> 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. <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 '_'.
 
 base64
   Converts a binary input sample to a base64 string. It is used to log or
@@ -11092,7 +11110,16 @@ debug
 div(<value>)
   Divides the input value of type signed integer by <value>, and returns the
   result as an signed integer. If <value> is null, the largest unsigned
-  integer is returned (typically 2^63-1).
+  integer is returned (typically 2^63-1). <value> 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([<avalanche>])
   Hashes a binary input sample into an unsigned 32-bit quantity using the DJB2
@@ -11287,11 +11314,29 @@ map_<match_type>_<output_type>(<map_file>[,<default_value>])
 mod(<value>)
   Divides the input value of type signed integer by <value>, and returns the
   remainder as an signed integer. If <value> is null, then zero is returned.
+  <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 '_'.
 
 mul(<value>)
   Multiplies the input value of type signed integer by <value>, 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.
+  <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 '_'.
 
 neg
   Takes the input value of type signed integer, computes the opposite value,
@@ -11311,7 +11356,16 @@ odd
 
 or(<value>)
   Performs a bitwise "OR" between <value> 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. <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 '_'.
 
 regsub(<regex>,<subst>[,<flags>])
   Applies a regex-based substitution to the input string. It does the same
@@ -11377,7 +11431,16 @@ set-var(<var name>)
 sub(<value>)
   Subtracts <value> 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)". <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(<table>)
   Uses the string representation of the input sample to perform a look up in
@@ -11559,6 +11622,15 @@ wt6([<avalanche>])
 xor(<value>)
   Performs a bitwise "XOR" (exclusive OR) between <value> and the input value
   of type signed integer, and returns the result as an signed integer.
+  <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 '_'.
 
 
 7.3.2. Fetching samples from internal states
index 41e754011aeab2532bd34cc9c16e946c089e99d2..eb005365cdb2d41a1ba4e83f29e6ecb357e5c157 100644 (file)
@@ -31,6 +31,7 @@
 #include <proto/proxy.h>
 #include <proto/sample.h>
 #include <proto/stick_table.h>
+#include <proto/vars.h>
 
 /* 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 },
 }};