mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-17 19:16:56 +00:00
MINOR: vars: Add 'unset-var' action/converter
It does the opposite of 'set-var' action/converter. It is really useful for per-process variables. But, it can be used for any scope. The lua function 'unset_var' has also been added.
This commit is contained in:
parent
ff2613ed7a
commit
85d79c94a9
@ -3655,6 +3655,7 @@ http-request { allow | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
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> |
|
||||
@ -3962,6 +3963,13 @@ http-request { allow | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
|
||||
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,
|
||||
@ -4119,6 +4127,7 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
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> |
|
||||
@ -4328,6 +4337,13 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
|
||||
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
|
||||
@ -9036,6 +9052,7 @@ tcp-request content <action> [{if | unless} <condition>]
|
||||
- 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"
|
||||
@ -9087,9 +9104,13 @@ tcp-request content <action> [{if | unless} <condition>]
|
||||
<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"
|
||||
@ -9242,6 +9263,9 @@ tcp-response content <action> [{if | unless} <condition>]
|
||||
- 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
|
||||
@ -9305,6 +9329,13 @@ tcp-response content <action> [{if | unless} <condition>]
|
||||
|
||||
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"
|
||||
@ -9353,6 +9384,7 @@ tcp-request session <action> [{if | unless} <condition>]
|
||||
- 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
|
||||
@ -12683,6 +12715,18 @@ url_dec
|
||||
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>
|
||||
|
@ -1419,7 +1419,13 @@ TXN class
|
||||
|
||||
:param class_txn txn: The class txn object containing the data.
|
||||
:param string var: The variable name according with the HAProxy variable syntax.
|
||||
:param opaque value: The data which is stored in the variable.
|
||||
|
||||
.. js:function:: TXN.unset_var(TXN, var)
|
||||
|
||||
Unset the variable <var>.
|
||||
|
||||
:param class_txn txn: The class txn object containing the data.
|
||||
:param string var: The variable name according with the HAProxy variable syntax.
|
||||
|
||||
.. js:function:: TXN.get_var(TXN, var)
|
||||
|
||||
|
@ -9,6 +9,8 @@ void vars_prune_per_sess(struct vars *vars);
|
||||
int vars_get_by_name(const char *name, size_t len, struct sample *smp);
|
||||
void vars_set_by_name_ifexist(const char *name, size_t len, struct sample *smp);
|
||||
void vars_set_by_name(const char *name, size_t len, struct sample *smp);
|
||||
void vars_unset_by_name_ifexist(const char *name, size_t len, struct sample *smp);
|
||||
void vars_unset_by_name(const char *name, size_t len, struct sample *smp);
|
||||
int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp);
|
||||
int vars_check_arg(struct arg *arg, char **err);
|
||||
|
||||
|
22
src/hlua.c
22
src/hlua.c
@ -4577,6 +4577,27 @@ __LJMP static int hlua_set_var(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_unset_var(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
const char *name;
|
||||
size_t len;
|
||||
struct sample smp;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "unset_var"));
|
||||
|
||||
/* It is useles to retrieve the stream, but this function
|
||||
* runs only in a stream context.
|
||||
*/
|
||||
htxn = MAY_LJMP(hlua_checktxn(L, 1));
|
||||
name = MAY_LJMP(luaL_checklstring(L, 2, &len));
|
||||
|
||||
/* Unset the variable. */
|
||||
smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
|
||||
vars_unset_by_name(name, len, &smp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_get_var(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
@ -6951,6 +6972,7 @@ void hlua_init(void)
|
||||
hlua_class_function(gL.T, "set_priv", hlua_set_priv);
|
||||
hlua_class_function(gL.T, "get_priv", hlua_get_priv);
|
||||
hlua_class_function(gL.T, "set_var", hlua_set_var);
|
||||
hlua_class_function(gL.T, "unset_var", hlua_unset_var);
|
||||
hlua_class_function(gL.T, "get_var", hlua_get_var);
|
||||
hlua_class_function(gL.T, "done", hlua_txn_done);
|
||||
hlua_class_function(gL.T, "set_loglevel",hlua_txn_set_loglevel);
|
||||
|
171
src/vars.c
171
src/vars.c
@ -86,6 +86,25 @@ static int var_accounting_add(struct vars *vars, struct session *sess, struct st
|
||||
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.
|
||||
*/
|
||||
@ -95,18 +114,7 @@ void vars_prune(struct vars *vars, struct session *sess, struct stream *strm)
|
||||
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);
|
||||
}
|
||||
@ -120,18 +128,7 @@ void vars_prune_per_sess(struct vars *vars)
|
||||
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;
|
||||
@ -398,12 +395,45 @@ static inline int sample_store_stream(const char *name, enum vars_scope scope, s
|
||||
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.
|
||||
@ -462,6 +492,37 @@ void vars_set_by_name(const char *name, size_t len, struct sample *smp)
|
||||
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.
|
||||
@ -567,6 +628,20 @@ static enum act_return action_store(struct act_rule *rule, struct proxy *px,
|
||||
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
|
||||
@ -601,18 +676,28 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy
|
||||
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;
|
||||
}
|
||||
|
||||
@ -620,6 +705,18 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy
|
||||
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,
|
||||
@ -708,32 +805,38 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
||||
}};
|
||||
|
||||
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 */ }
|
||||
}};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user