del-map(<file name>) <key fmt> |
set-map(<file name>) <key fmt> <value fmt> |
set-var(<var name>) <expr> |
+ unset-var(<var name>) |
{ track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] |
sc-inc-gpc0(<sc-id>) |
sc-set-gpt0(<sc-id>) <int> |
http-request set-var(req.my_var) req.fhdr(user-agent),lower
+ - unset-var(<var-name>) :
+ Is used to unset a variable. See above for details about <var-name>.
+
+ Example:
+
+ http-request unset-var(req.my_var)
+
- set-src <expr> :
Is used to set the source IP address to the value of specified
expression. Useful when a proxy in front of HAProxy rewrites source IP,
del-map(<file name>) <key fmt> |
set-map(<file name>) <key fmt> <value fmt> |
set-var(<var-name>) <expr> |
+ unset-var(<var-name>) |
{ track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] |
sc-inc-gpc0(<sc-id>) |
sc-set-gpt0(<sc-id>) <int> |
http-response set-var(sess.last_redir) res.hdr(location)
+ - unset-var(<var-name>) :
+ Is used to unset a variable. See above for details about <var-name>.
+
+ Example:
+
+ http-response unset-var(sess.last_redir)
+
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] :
enables tracking of sticky counters from current response. Please refer to
"http-request track-sc" for a complete description. The only difference
- sc-inc-gpc0(<sc-id>)
- sc-set-gpt0(<sc-id>) <int>
- set-var(<var-name>) <expr>
+ - unset-var(<var-name>)
- silent-drop
They have the same meaning as their counter-parts in "tcp-request connection"
<expr> Is a standard HAProxy expression formed by a sample-fetch
followed by some converters.
+ The "unset-var" is used to unset a variable. See above for details about
+ <var-name>.
+
Example:
tcp-request content set-var(sess.my_var) src
+ tcp-request content unset-var(sess.my_var2)
Example:
# Accept HTTP requests containing a Host header saying "example.com"
- set-var(<var-name>) <expr>
Sets a variable.
+ - unset-var(<var-name>)
+ Unsets a variable.
+
- sc-inc-gpc0(<sc-id>):
This action increments the GPC0 counter according to the sticky
counter designated by <sc-id>. If an error occurs, this action fails
tcp-request content set-var(sess.my_var) src
+ The "unset-var" is used to unset a variable. See above for details about
+ <var-name>.
+
+ Example:
+
+ tcp-request content unset-var(sess.my_var)
+
See section 7 about ACL usage.
See also : "tcp-request content", "tcp-response inspect-delay"
- sc-inc-gpc0(<sc-id>)
- sc-set-gpt0(<sc-id>) <int>
- set-var(<var-name>) <expr>
+ - unset-var(<var-name>)
- silent-drop
These actions have the same meaning as their respective counter-parts in
Takes an url-encoded string provided as input and returns the decoded
version as output. The input and the output are of type string.
+unset-var(<var name>)
+ Unsets a variable if the input content is defined. The name of the variable
+ starts with an indication about its scope. The scopes allowed are:
+ "proc" : the variable is shared with the whole process
+ "sess" : the variable is shared with the whole session
+ "txn" : the variable is shared with the transaction (request and
+ response),
+ "req" : the variable is shared only during request processing,
+ "res" : the variable is shared only during 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 '_'.
+
utime(<format>[,<offset>])
Converts an integer supposed to contain a date since epoch to a string
representing this date in UTC time using a format defined by the <format>
return 1;
}
+/* This fnuction remove a variable from the list and free memory it used */
+unsigned int var_clear(struct var *var)
+{
+ unsigned int size = 0;
+
+ if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
+ free(var->data.u.str.str);
+ size += var->data.u.str.len;
+ }
+ else if (var->data.type == SMP_T_METH) {
+ free(var->data.u.meth.str.str);
+ size += var->data.u.meth.str.len;
+ }
+ LIST_DEL(&var->l);
+ pool_free2(var_pool, var);
+ size += sizeof(struct var);
+ return size;
+}
+
/* This function free all the memory used by all the varaibles
* in the list.
*/
unsigned int size = 0;
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.u.str.str);
- size += var->data.u.str.len;
- }
- else if (var->data.type == SMP_T_METH) {
- free(var->data.u.meth.str.str);
- size += var->data.u.meth.str.len;
- }
- LIST_DEL(&var->l);
- pool_free2(var_pool, var);
- size += sizeof(struct var);
+ size += var_clear(var);
}
var_accounting_diff(vars, sess, strm, -size);
}
unsigned int size = 0;
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.u.str.str);
- size += var->data.u.str.len;
- }
- else if (var->data.type == SMP_T_METH) {
- free(var->data.u.meth.str.str);
- size += var->data.u.meth.str.len;
- }
- LIST_DEL(&var->l);
- pool_free2(var_pool, var);
- size += sizeof(struct var);
+ size += var_clear(var);
}
vars->size -= size;
global.vars.size -= size;
return sample_store(vars, name, smp);
}
+/* Returns 0 if fails, else returns 1. Note that stream may be null for SCOPE_SESS. */
+static inline int sample_clear_stream(const char *name, enum vars_scope scope, struct sample *smp)
+{
+ struct vars *vars;
+ struct var *var;
+ unsigned int size = 0;
+
+ switch (scope) {
+ case SCOPE_PROC: vars = &global.vars; break;
+ case SCOPE_SESS: vars = &smp->sess->vars; break;
+ case SCOPE_TXN: vars = &smp->strm->vars_txn; break;
+ case SCOPE_REQ:
+ case SCOPE_RES:
+ default: vars = &smp->strm->vars_reqres; break;
+ }
+ if (vars->scope != scope)
+ return 0;
+
+ /* Look for existing variable name. */
+ var = var_get(vars, name);
+ if (var) {
+ size = var_clear(var);
+ var_accounting_diff(vars, smp->sess, smp->strm, -size);
+ }
+ return 1;
+}
+
/* 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[0].data.var.scope, smp);
}
+/* Returns 0 if fails, else returns 1. */
+static int smp_conv_clear(const struct arg *args, struct sample *smp, void *private)
+{
+ return sample_clear_stream(args[0].data.var.name, args[0].data.var.scope, 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.
sample_store_stream(name, scope, smp);
}
+/* This function unset a variable if it was already defined.
+ * In error case, it fails silently.
+ */
+void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp)
+{
+ enum vars_scope scope;
+
+ /* Resolve name and scope. */
+ name = register_name(name, len, &scope, 0, NULL);
+ if (!name)
+ return;
+
+ sample_clear_stream(name, scope, smp);
+}
+
+
+/* This function unset a variable.
+ * In error case, it fails silently.
+ */
+void vars_unset_by_name(const char *name, size_t len, struct sample *smp)
+{
+ enum vars_scope scope;
+
+ /* Resolve name and scope. */
+ name = register_name(name, len, &scope, 1, NULL);
+ if (!name)
+ return;
+
+ sample_clear_stream(name, scope, smp);
+}
+
/* this function fills a sample with the
* variable content. Returns 1 if the sample
* is filled, otherwise it returns 0.
return ACT_RET_CONT;
}
+/* Always returns ACT_RET_CONT even if an error occurs. */
+static enum act_return action_clear(struct act_rule *rule, struct proxy *px,
+ struct session *sess, struct stream *s, int flags)
+{
+ struct sample smp;
+
+ memset(&smp, 0, sizeof(smp));
+ smp_set_owner(&smp, px, sess, s, SMP_OPT_FINAL);
+
+ /* Clear the variable using the sample context, and ignore errors. */
+ sample_clear_stream(rule->arg.vars.name, rule->arg.vars.scope, &smp);
+ return ACT_RET_CONT;
+}
+
/* 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
const char *var_name = args[*arg-1];
int var_len;
const char *kw_name;
- int flags;
+ int flags, set_var;
+
+ if (!strncmp(var_name, "set-var", 7)) {
+ var_name += 7;
+ set_var = 1;
+ }
+ if (!strncmp(var_name, "unset-var", 9)) {
+ var_name += 9;
+ set_var = 0;
+ }
- var_name += strlen("set-var");
if (*var_name != '(') {
- memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)'", args[*arg-1]);
+ memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
+ args[*arg-1]);
return ACT_RET_PRS_ERR;
}
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]);
+ memprintf(err, "invalid variable '%s'. Expects 'set-var(<var-name>)' or 'unset-var(<var-name>)'",
+ args[*arg-1]);
return ACT_RET_PRS_ERR;
}
if (!rule->arg.vars.name)
return ACT_RET_PRS_ERR;
+ /* There is no fetch method when variable is unset. Just set the right
+ * action and return. */
+ if (!set_var) {
+ if (*args[*arg]) {
+ memprintf(err, "fetch method not supported");
+ return ACT_RET_PRS_ERR;
+ }
+ rule->action = ACT_CUSTOM;
+ rule->action_ptr = action_clear;
+ return ACT_RET_PRS_OK;
+ }
+
kw_name = args[*arg-1];
rule->arg.vars.expr = sample_parse_expr((char **)args, arg, px->conf.args.file,
}};
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 },
+ { "set-var", smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
+ { "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
{ /* END */ },
}};
static struct action_kw_list tcp_req_sess_kws = { { }, {
- { "set-var", parse_store, 1 },
+ { "set-var", parse_store, 1 },
+ { "unset-var", parse_store, 1 },
{ /* END */ }
}};
static struct action_kw_list tcp_req_cont_kws = { { }, {
- { "set-var", parse_store, 1 },
+ { "set-var", parse_store, 1 },
+ { "unset-var", parse_store, 1 },
{ /* END */ }
}};
static struct action_kw_list tcp_res_kws = { { }, {
- { "set-var", parse_store, 1 },
+ { "set-var", parse_store, 1 },
+ { "unset-var", parse_store, 1 },
{ /* END */ }
}};
static struct action_kw_list http_req_kws = { { }, {
- { "set-var", parse_store, 1 },
+ { "set-var", parse_store, 1 },
+ { "unset-var", parse_store, 1 },
{ /* END */ }
}};
static struct action_kw_list http_res_kws = { { }, {
- { "set-var", parse_store, 1 },
+ { "set-var", parse_store, 1 },
+ { "unset-var", parse_store, 1 },
{ /* END */ }
}};