- tune.ssl.maxrecord
- tune.ssl.default-dh-param
- tune.ssl.ssl-ctx-cache-size
+ - tune.vars.global-max-size
+ - tune.vars.reqres-max-size
+ - tune.vars.sess-max-size
+ - tune.vars.txn-max-size
- tune.zlib.memlevel
- tune.zlib.windowsize
dynamically is expensive, they are cached. The default cache size is set to
1000 entries.
+tune.vars.global-max-size <size>
+tune.vars.reqres-max-size <size>
+tune.vars.sess-max-size <size>
+tune.vars.txn-max-size <size>
+ These four tunes helps to manage the allowed amount of memory used by the
+ variables system. "global" limits the memory for all the systems. "sess" limit
+ the memory by session, "txn" limits the memory by transaction and "reqres"
+ limits the memory for each request or response processing. during the
+ accounting, "sess" embbed "txn" and "txn" embed "reqres".
+
+ By example, we considers that "tune.vars.sess-max-size" is fixed to 100,
+ "tune.vars.txn-max-size" is fixed to 100, "tune.vars.reqres-max-size" is
+ also fixed to 100. If we create a variable "txn.var" that contains 100 bytes,
+ we cannot create any more variable in the other contexts.
+
tune.zlib.memlevel <number>
Sets the memLevel parameter in zlib initialization for each session. It
defines how much memory should be allocated for the internal compression
del-acl(<file name>) <key fmt> |
del-map(<file name>) <key fmt> |
set-map(<file name>) <key fmt> <value fmt> |
+ set-var(<var name>) <expr> |
{ track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] |
lua <function name>
}
parameter is the name of the function to run. The prototype of the
function is documented in the API documentation.
+ - set-var(<var-name>) <expr> :
+ Is used to set the contents of a variable. The variable is declared
+ inline.
+
+ <var-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 '_'.
+
+ <expr> Is a standard HAProxy expression formed by a sample-fetch
+ followed by some converters.
+
+ Example:
+
+ http-request set-var(req.my_var) req.fhdr(user-agent),lower
+
There is no limit to the number of http-request statements per instance.
It is important to know that http-request rules are processed very early in
del-acl(<file name>) <key fmt> |
del-map(<file name>) <key fmt> |
set-map(<file name>) <key fmt> <value fmt> |
+ set-var(<var-name>) <expr> |
lua <function name>
}
[ { if | unless } <condition> ]
a redirect rule is applied during a response, connections to the server
are closed so that no data can be forwarded from the server to the client.
+ - set-var(<var-name>) expr:
+ Is used to set the contents of a variable. The variable is declared
+ inline.
+
+ <var-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 '_'.
+
+ <expr> Is a standard HAProxy expression formed by a sample-fetch
+ followed by some converters.
+
+ Example:
+
+ http-response set-var(sess.last_redir) res.hdr(location)
+
There is no limit to the number of http-response statements per instance.
It is important to know that http-response rules are processed very early in
- capture : the specified sample expression is captured
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]
- lua <function>
+ - set-var(<var-name>) <expr>
They have the same meaning as their counter-parts in "tcp-request connection"
so please refer to that section for a complete description.
function to run. The prototype of the function is documented in the API
documentation.
+ The "set-var" is used to set the content of a variable. The variable is
+ declared inline.
+
+ <var-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 '_'.
+
+ <expr> Is a standard HAProxy expression formed by a sample-fetch
+ followed by some converters.
+
+ Example:
+
+ tcp-request content set-var(sess.my_var) src
+
Example:
# Accept HTTP requests containing a Host header saying "example.com"
# and reject everything else.
- lua <function>
Executes Lua.
+ - set-var(<var-name>) <expr>
+ Sets a variable.
+
Note that the "if/unless" condition is optional. If no condition is set on
the action, it is simply performed unconditionally. That can be useful for
for changing the default action to a reject.
function to run. The prototype of the function is documented in the API
documentation.
+ The "set-var" is used to set the content of a variable. The variable is
+ declared inline.
+
+ <var-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 '_'.
+
+ <expr> Is a standard HAProxy expression formed by a sample-fetch
+ followed by some converters.
+
+ Example:
+
+ tcp-request content set-var(sess.my_var) src
+
See section 7 about ACL usage.
See also : "tcp-request content", "tcp-response inspect-delay"
32-bit hash is trivial to break. See also "crc32", "djb2", "wt6" and the
"hash-type" directive.
+set-var(<var name>)
+ Sets a variable with the input content and return the content on the output as
+ is. The variable keep the value and the associated input type. 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 '_'.
+
sub(<value>)
Subtracts <value> from the input value of type unsigned integer, and returns
the result as an unsigned integer. Note: in order to subtract the input from
stick-table or in the designated stick-table. See also src_conn_cnt and
table_avl for other entry counting methods.
+var(<var-name>) : undefined
+ Returns a variable with the stored type. If the variable is not set, the
+ sample fetch fails. The name of the variable starts by an indication about its
+ 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 '_'.
+
7.3.3. Fetching samples at Layer 4
----------------------------------
--- /dev/null
+#include <ctype.h>
+
+#include <common/cfgparse.h>
+#include <common/mini-clist.h>
+
+#include <types/vars.h>
+
+#include <proto/arg.h>
+#include <proto/proto_http.h>
+#include <proto/proto_tcp.h>
+#include <proto/sample.h>
+#include <proto/stream.h>
+
+/* This contains a pool of struct vars */
+static struct pool_head *var_pool = NULL;
+
+/* This array contain all the names of all the HAProxy vars.
+ * This permits to identify two variables name with
+ * only one pointer. It permits to not using strdup() for
+ * each variable name used during the runtime.
+ */
+static char **var_names = NULL;
+static int var_names_nb = 0;
+
+/* This array of int contains the system limits per context. */
+static unsigned int var_global_limit = 0;
+static unsigned int var_global_size = 0;
+static unsigned int var_sess_limit = 0;
+static unsigned int var_txn_limit = 0;
+static unsigned int var_reqres_limit = 0;
+
+/* This function adds or remove memory size from the accounting. */
+static void var_accounting_diff(struct vars *vars, struct stream *strm, int size)
+{
+ switch (vars->scope) {
+ case SCOPE_REQ:
+ case SCOPE_RES:
+ strm->vars_reqres.size += size;
+ case SCOPE_TXN:
+ strm->vars_txn.size += size;
+ case SCOPE_SESS:
+ strm->vars_sess.size += size;
+ var_global_size += size;
+ }
+}
+
+/* This function returns 1 if the <size> is available in the var
+ * pool <vars>, otherwise returns 0. If the space is avalaible,
+ * the size is reserved.
+ */
+static int var_accounting_add(struct vars *vars, struct stream *strm, int size)
+{
+ switch (vars->scope) {
+ case SCOPE_REQ:
+ case SCOPE_RES:
+ if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit)
+ return 0;
+ case SCOPE_TXN:
+ if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit)
+ return 0;
+ case SCOPE_SESS:
+ if (var_sess_limit && strm->vars_sess.size + size > var_sess_limit)
+ return 0;
+ if (var_global_limit && var_global_size + size > var_global_limit)
+ return 0;
+ }
+ var_accounting_diff(vars, strm, size);
+ return 1;
+}
+
+/* This function free all the memory used by all the varaibles
+ * in the list.
+ */
+void vars_prune(struct vars *vars, struct stream *strm)
+{
+ struct var *var, *tmp;
+
+ list_for_each_entry_safe(var, tmp, &vars->head, l) {
+ if (var->data.type == SMP_T_STR ||
+ var->data.type == SMP_T_BIN) {
+ free(var->data.data.str.str);
+ var_accounting_diff(vars, strm, -var->data.data.str.len);
+ }
+ else if (var->data.type == SMP_T_METH) {
+ free(var->data.data.meth.str.str);
+ var_accounting_diff(vars, strm, -var->data.data.meth.str.len);
+ }
+ LIST_DEL(&var->l);
+ pool_free2(var_pool, var);
+ var_accounting_diff(vars, strm, -(int)sizeof(struct var));
+ }
+}
+
+/* This function init a list of variabes. */
+void vars_init(struct vars *vars, enum vars_scope scope)
+{
+ LIST_INIT(&vars->head);
+ vars->scope = scope;
+ vars->size = 0;
+}
+
+/* This function declares a new variable name. It returns a pointer
+ * on the string identifying the name. This function assures that
+ * the same name exists only once.
+ *
+ * This function check if the variable name is acceptable.
+ *
+ * The function returns NULL if an error occurs, and <err> is filled.
+ * In this case, the HAProxy must be stopped because the structs are
+ * left inconsistent. Otherwise, it returns the pointer on the global
+ * name.
+ */
+static char *register_name(const char *name, int len, enum vars_scope *scope, char **err)
+{
+ int i;
+ const char *tmp;
+
+ /* Check length. */
+ if (len == 0) {
+ memprintf(err, "Empty variable name cannot be accepted");
+ return NULL;
+ }
+
+ /* Check scope. */
+ if (len > 5 && strncmp(name, "sess.", 5) == 0) {
+ name += 5;
+ len -= 5;
+ *scope = SCOPE_SESS;
+ }
+ else if (len > 4 && strncmp(name, "txn.", 4) == 0) {
+ name += 4;
+ len -= 4;
+ *scope = SCOPE_TXN;
+ }
+ else if (len > 4 && strncmp(name, "req.", 4) == 0) {
+ name += 4;
+ len -= 4;
+ *scope = SCOPE_REQ;
+ }
+ else if (len > 4 && strncmp(name, "res.", 4) == 0) {
+ name += 4;
+ len -= 4;
+ *scope = SCOPE_RES;
+ }
+ else {
+ memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
+ "The scope can be 'sess', 'txn', 'req' or 'res'", name);
+ return NULL;
+ }
+
+ /* Look for existing variable name. */
+ for (i = 0; i < var_names_nb; i++)
+ if (strncmp(var_names[i], name, len) == 0)
+ return var_names[i];
+
+ /* Store variable name. */
+ var_names_nb++;
+ var_names = realloc(var_names, var_names_nb * sizeof(*var_names));
+ if (!var_names) {
+ memprintf(err, "out of memory error");
+ return NULL;
+ }
+ var_names[var_names_nb - 1] = malloc(len + 1);
+ if (!var_names[var_names_nb - 1]) {
+ memprintf(err, "out of memory error");
+ return NULL;
+ }
+ memcpy(var_names[var_names_nb - 1], name, len);
+ var_names[var_names_nb - 1][len] = '\0';
+
+ /* Check variable name syntax. */
+ tmp = var_names[var_names_nb - 1];
+ while (*tmp) {
+ if (!isalnum((int)(unsigned char)*tmp) && *tmp != '_') {
+ memprintf(err, "invalid syntax at char '%s'", tmp);
+ return NULL;
+ }
+ tmp++;
+ }
+
+ /* Return the result. */
+ return var_names[var_names_nb - 1];
+}
+
+/* This function returns an existing variable or returns NULL. */
+static inline struct var *var_get(struct vars *vars, const char *name)
+{
+ struct var *var;
+
+ list_for_each_entry(var, &vars->head, l)
+ if (var->name == name)
+ return var;
+ return NULL;
+}
+
+/* Returns 0 if fails, else returns 1. */
+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;
+ struct var *var;
+ struct vars *vars;
+
+ /* Check the availibity of the variable. */
+ switch (var_desc->scope) {
+ case SCOPE_SESS: vars = &smp->strm->vars_sess; break;
+ case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
+ case SCOPE_REQ:
+ case SCOPE_RES: vars = &smp->strm->vars_reqres; break;
+ }
+ if (vars->scope != var_desc->scope)
+ return 0;
+ var = var_get(vars, var_desc->name);
+
+ /* check for the variable avalaibility */
+ if (!var)
+ return 0;
+
+ /* Copy sample. */
+ smp->type = var->data.type;
+ smp->flags |= SMP_F_CONST;
+ memcpy(&smp->data, &var->data.data, sizeof(smp->data));
+ return 1;
+}
+
+/* This function search in the <head> a variable with the same
+ * pointer value that the <name>. If the variable doesn't exists,
+ * create it. The function stores a copy of smp> if the variable.
+ * It returns 0 if fails, else returns 1.
+ */
+static int sample_store(struct vars *vars, const char *name, struct stream *strm, struct sample *smp)
+{
+ struct var *var;
+
+ /* Look for existing variable name. */
+ var = var_get(vars, name);
+
+ if (var) {
+ /* free its used memory. */
+ if (var->data.type == SMP_T_STR ||
+ var->data.type == SMP_T_BIN) {
+ free(var->data.data.str.str);
+ var_accounting_diff(vars, strm, -var->data.data.str.len);
+ }
+ else if (var->data.type == SMP_T_METH) {
+ free(var->data.data.meth.str.str);
+ var_accounting_diff(vars, strm, -var->data.data.meth.str.len);
+ }
+ } else {
+
+ /* Check memory avalaible. */
+ if (!var_accounting_add(vars, strm, sizeof(struct var)))
+ return 0;
+
+ /* Create new entry. */
+ var = pool_alloc2(var_pool);
+ if (!var)
+ return 0;
+ LIST_ADDQ(&vars->head, &var->l);
+ var->name = name;
+ }
+
+ /* Set type. */
+ var->data.type = smp->type;
+
+ /* Copy data. If the data needs memory, the function can fail. */
+ switch (var->data.type) {
+ case SMP_T_BOOL:
+ case SMP_T_UINT:
+ case SMP_T_SINT:
+ var->data.data.sint = smp->data.sint;
+ break;
+ case SMP_T_IPV4:
+ var->data.data.ipv4 = smp->data.ipv4;
+ break;
+ case SMP_T_IPV6:
+ var->data.data.ipv6 = smp->data.ipv6;
+ break;
+ case SMP_T_STR:
+ case SMP_T_BIN:
+ if (!var_accounting_add(vars, strm, smp->data.str.len)) {
+ var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
+ return 0;
+ }
+ var->data.data.str.str = malloc(smp->data.str.len);
+ if (!var->data.data.str.str) {
+ var_accounting_diff(vars, strm, -smp->data.str.len);
+ var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
+ return 0;
+ }
+ var->data.data.str.len = smp->data.str.len;
+ memcpy(var->data.data.str.str, smp->data.str.str, var->data.data.str.len);
+ break;
+ case SMP_T_METH:
+ if (!var_accounting_add(vars, strm, smp->data.meth.str.len)) {
+ var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
+ return 0;
+ }
+ var->data.data.meth.str.str = malloc(smp->data.meth.str.len);
+ if (!var->data.data.meth.str.str) {
+ var_accounting_diff(vars, strm, -smp->data.meth.str.len);
+ var->data.type = SMP_T_BOOL; /* This type doesn't use additional memory. */
+ return 0;
+ }
+ var->data.data.meth.meth = smp->data.meth.meth;
+ var->data.data.meth.str.len = smp->data.meth.str.len;
+ var->data.data.meth.str.size = smp->data.meth.str.len;
+ memcpy(var->data.data.meth.str.str, smp->data.meth.str.str, var->data.data.meth.str.len);
+ break;
+ }
+ return 1;
+}
+
+/* Returns 0 if fails, else returns 1. */
+static inline int sample_store_stream(const char *name, enum vars_scope scope,
+ struct stream *strm, struct sample *smp)
+{
+ struct vars *vars;
+
+ switch (scope) {
+ case SCOPE_SESS: vars = &strm->vars_sess; break;
+ case SCOPE_TXN: vars = &strm->vars_txn; break;
+ case SCOPE_REQ:
+ case SCOPE_RES: vars = &strm->vars_reqres; break;
+ }
+ if (vars->scope != scope)
+ return 0;
+ return sample_store(vars, name, strm, smp);
+}
+
+/* Returns 0 if fails, else returns 1. */
+static int smp_conv_store(const struct arg *args, struct sample *smp, void *private)
+{
+ return sample_store_stream(args[0].data.var.name, args[1].data.var.scope, smp->strm, smp);
+}
+
+/* This fucntions check an argument entry and fill it with a variable
+ * type. The argumen must be a string. If the variable lookup fails,
+ * the function retuns 0 and fill <err>, otherwise it returns 1.
+ */
+int vars_check_arg(struct arg *arg, char **err)
+{
+ char *name;
+ enum vars_scope scope;
+
+ /* Check arg type. */
+ if (arg->type != ARGT_STR) {
+ memprintf(err, "unexpected argument type");
+ return 0;
+ }
+
+ /* Register new variable name. */
+ name = register_name(arg->data.str.str, arg->data.str.len, &scope, err);
+ if (!name)
+ return 0;
+
+ /* Use the global variable name pointer. */
+ arg->type = ARGT_VAR;
+ arg->data.var.name = name;
+ arg->data.var.scope = scope;
+ return 1;
+}
+
+/* Returns 0 if miss data, else returns 1. */
+static inline int action_store(struct sample_expr *expr, const char *name,
+ enum vars_scope scope, struct proxy *px,
+ struct stream *s, int sens)
+{
+ struct sample smp;
+
+ /* Process the expression. */
+ memset(&smp, 0, sizeof(smp));
+ if (!sample_process(px, s->sess, s, sens|SMP_OPT_FINAL, expr, &smp))
+ return 0;
+
+ /* Store the sample, and ignore errors. */
+ sample_store_stream(name, scope, s, &smp);
+ return 1;
+}
+
+/* Returns 0 if miss data, else returns 1. */
+static int action_tcp_req_store(struct tcp_rule *rule, struct proxy *px, struct stream *s)
+{
+ struct sample_expr *expr = rule->act_prm.data[0];
+ const char *name = rule->act_prm.data[1];
+ int scope = (long)rule->act_prm.data[2];
+
+ return action_store(expr, name, scope, px, s, SMP_OPT_DIR_REQ);
+}
+
+/* Returns 0 if miss data, else returns 1. */
+static int action_tcp_res_store(struct tcp_rule *rule, struct proxy *px, struct stream *s)
+{
+ struct sample_expr *expr = rule->act_prm.data[0];
+ const char *name = rule->act_prm.data[1];
+ int scope = (long)rule->act_prm.data[2];
+
+ return action_store(expr, name, scope, px, s, SMP_OPT_DIR_RES);
+}
+
+/* Returns 0 if miss data, else returns 1. */
+static int action_http_req_store(struct http_req_rule *rule, struct proxy *px, struct stream *s)
+{
+ struct sample_expr *expr = rule->arg.act.p[0];
+ const char *name = rule->arg.act.p[1];
+ int scope = (long)rule->arg.act.p[2];
+
+ return action_store(expr, name, scope, px, s, SMP_OPT_DIR_REQ);
+}
+
+/* Returns 0 if miss data, else returns 1. */
+static int action_http_res_store(struct http_res_rule *rule, struct proxy *px, struct stream *s)
+{
+ struct sample_expr *expr = rule->arg.act.p[0];
+ const char *name = rule->arg.act.p[1];
+ int scope = (long)rule->arg.act.p[2];
+
+ return action_store(expr, name, scope, px, s, SMP_OPT_DIR_RES);
+}
+
+/* This two function checks the variable name and replace the
+ * configuration string name by the global string name. its
+ * the same string, but the global pointer can be easy to
+ * compare.
+ *
+ * The first function checks a sample-fetch and the second
+ * checks a converter.
+ */
+static int smp_check_var(struct arg *args, char **err)
+{
+ return vars_check_arg(&args[0], err);
+}
+
+static int conv_check_var(struct arg *args, struct sample_conv *conv,
+ const char *file, int line, char **err_msg)
+{
+ return vars_check_arg(&args[0], err_msg);
+}
+
+/* This function is a common parser for using variables. It understands
+ * the format:
+ *
+ * set-var(<variable-name>) <expression>
+ *
+ * It returns 0 if fails and <err> is filled with an error message. Otherwise,
+ * it returns 1 and the variable <expr> is filled with the pointer to the
+ * expression to execute.
+ */
+static int parse_vars(const char **args, int *arg, struct proxy *px,
+ struct sample_expr **expr, char **name,
+ enum vars_scope *scope, char **err)
+{
+ const char *var_name = args[*arg-1];
+ int var_len;
+
+ var_name += strlen("set-var");
+ if (*var_name != '(') {
+ memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
+ return 0;
+ }
+ var_name++; /* jump the '(' */
+ var_len = strlen(var_name);
+ var_len--; /* remove the ')' */
+ if (var_name[var_len] != ')') {
+ memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
+ return 0;
+ }
+
+ *name = register_name(var_name, var_len, scope, err);
+ if (!*name)
+ return 0;
+
+ *expr = sample_parse_expr((char **)args, arg, px->conf.args.file, px->conf.args.line,
+ err, &px->conf.args);
+ if (!*expr)
+ return 0;
+
+ return 1;
+}
+
+static int parse_tcp_req_store(const char **args, int *arg, struct proxy *px,
+ struct tcp_rule *rule, char **err)
+{
+ struct sample_expr *expr;
+ int cur_arg = *arg;
+ char *name;
+ enum vars_scope scope;
+
+ if (!parse_vars(args, arg, px, &expr, &name, &scope, err))
+ return 0;
+
+ if (!(expr->fetch->val & SMP_VAL_FE_REQ_CNT)) {
+ memprintf(err,
+ "fetch method '%s' extracts information from '%s', none of which is available here",
+ args[cur_arg-1], sample_src_names(expr->fetch->use));
+ free(expr);
+ return 0;
+ }
+
+ rule->action = TCP_ACT_CUSTOM_CONT;
+ rule->action_ptr = action_tcp_req_store;
+ rule->act_prm.data[0] = expr;
+ rule->act_prm.data[1] = name;
+ rule->act_prm.data[2] = (void *)(long)scope;
+
+ return 1;
+}
+
+static int parse_tcp_res_store(const char **args, int *arg, struct proxy *px,
+ struct tcp_rule *rule, char **err)
+{
+ struct sample_expr *expr;
+ int cur_arg = *arg;
+ char *name;
+ enum vars_scope scope;
+
+ if (!parse_vars(args, arg, px, &expr, &name, &scope, err))
+ return 0;
+
+ if (!(expr->fetch->val & SMP_VAL_BE_RES_CNT)) {
+ memprintf(err,
+ "fetch method '%s' extracts information from '%s', none of which is available here",
+ args[cur_arg-1], sample_src_names(expr->fetch->use));
+ free(expr);
+ return 0;
+ }
+
+ rule->action = TCP_ACT_CUSTOM_CONT;
+ rule->action_ptr = action_tcp_res_store;
+ rule->act_prm.data[0] = expr;
+ rule->act_prm.data[1] = name;
+ rule->act_prm.data[2] = (void *)(long)scope;
+
+ return 1;
+}
+
+static int parse_http_req_store(const char **args, int *arg, struct proxy *px,
+ struct http_req_rule *rule, char **err)
+{
+ struct sample_expr *expr;
+ int cur_arg = *arg;
+ char *name;
+ enum vars_scope scope;
+
+ if (!parse_vars(args, arg, px, &expr, &name, &scope, err))
+ return -1;
+
+ if (!(expr->fetch->val & SMP_VAL_FE_HRQ_HDR)) {
+ memprintf(err,
+ "fetch method '%s' extracts information from '%s', none of which is available here",
+ args[cur_arg-1], sample_src_names(expr->fetch->use));
+ free(expr);
+ return -1;
+ }
+
+ rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
+ rule->action_ptr = action_http_req_store;
+ rule->arg.act.p[0] = expr;
+ rule->arg.act.p[1] = name;
+ rule->arg.act.p[2] = (void *)(long)scope;
+
+ return 0;
+}
+
+static int parse_http_res_store(const char **args, int *arg, struct proxy *px,
+ struct http_res_rule *rule, char **err)
+{
+ struct sample_expr *expr;
+ int cur_arg = *arg;
+ char *name;
+ enum vars_scope scope;
+
+ if (!parse_vars(args, arg, px, &expr, &name, &scope, err))
+ return -1;
+
+ if (!(expr->fetch->val & SMP_VAL_BE_HRS_HDR)) {
+ memprintf(err,
+ "fetch method '%s' extracts information from '%s', none of which is available here",
+ args[cur_arg-1], sample_src_names(expr->fetch->use));
+ free(expr);
+ return -1;
+ }
+
+ rule->action = HTTP_RES_ACT_CUSTOM_CONT;
+ rule->action_ptr = action_http_res_store;
+ rule->arg.act.p[0] = expr;
+ rule->arg.act.p[1] = name;
+ rule->arg.act.p[2] = (void *)(long)scope;
+
+ return 0;
+}
+
+static int vars_max_size(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err, unsigned int *limit)
+{
+ char *error;
+
+ *limit = strtol(args[1], &error, 10);
+ if (*error != 0) {
+ memprintf(err, "%s: '%s' is an invalid size", args[0], args[1]);
+ return -1;
+ }
+ return 0;
+}
+
+static int vars_max_size_global(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_global_limit);
+}
+
+static int vars_max_size_sess(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_sess_limit);
+}
+
+static int vars_max_size_txn(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_txn_limit);
+}
+
+static int vars_max_size_reqres(char **args, int section_type, struct proxy *curpx,
+ struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
+}
+
+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_HTTP_ANY },
+ { /* END */ },
+}};
+
+static struct sample_conv_kw_list sample_conv_kws = {ILH, {
+ { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
+ { /* END */ },
+}};
+
+static struct tcp_action_kw_list tcp_req_kws = {"vars", { }, {
+ { "set-var", parse_tcp_req_store, 1 },
+ { /* END */ }
+}};
+
+static struct tcp_action_kw_list tcp_res_kws = {"vars", { }, {
+ { "set-var", parse_tcp_res_store, 1 },
+ { /* END */ }
+}};
+
+static struct http_req_action_kw_list http_req_kws = {"vars", { }, {
+ { "set-var", parse_http_req_store, 1 },
+ { /* END */ }
+}};
+
+static struct http_res_action_kw_list http_res_kws = {"vars", { }, {
+ { "set-var", parse_http_res_store, 1 },
+ { /* END */ }
+}};
+
+static struct cfg_kw_list cfg_kws = {{ },{
+ { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
+ { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },
+ { CFG_GLOBAL, "tune.vars.txn-max-size", vars_max_size_txn },
+ { CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
+ { /* END */ }
+}};
+
+__attribute__((constructor))
+static void __http_protocol_init(void)
+{
+ var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
+
+ sample_register_fetches(&sample_fetch_keywords);
+ sample_register_convs(&sample_conv_kws);
+ tcp_req_cont_keywords_register(&tcp_req_kws);
+ tcp_res_cont_keywords_register(&tcp_res_kws);
+ http_req_keywords_register(&http_req_kws);
+ http_res_keywords_register(&http_res_kws);
+ cfg_register_keywords(&cfg_kws);
+}