mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-08 22:50:02 +00:00
MEDIUM: lua: Add ifexist
parameter to set_var
As discussed in GitHub issue #624 Lua scripts should not use variables that are never going to be read, because the memory for variable names is never going to be freed. Add an optional `ifexist` parameter to the `set_var` function that allows a Lua developer to set variables that are going to be ignored if the variable name was not used elsewhere before. Usually this mean that there is no `var()` sample fetch for the variable in question within the configuration.
This commit is contained in:
parent
84ebc136a1
commit
4e172c93f9
@ -1710,7 +1710,7 @@ TXN class
|
||||
:param class_txn txn: The class txn object containing the data.
|
||||
:param opaque data: The data which is stored in the transaction.
|
||||
|
||||
.. js:function:: TXN.set_var(TXN, var, value)
|
||||
.. js:function:: TXN.set_var(TXN, var, value[, ifexist])
|
||||
|
||||
Converts a Lua type in a HAProxy type and store it in a variable <var>.
|
||||
|
||||
@ -1718,6 +1718,10 @@ TXN class
|
||||
:param string var: The variable name according with the HAProxy variable syntax.
|
||||
:param type value: The value associated to the variable. The type can be string or
|
||||
integer.
|
||||
:param boolean ifexist: If this parameter is set to a truthy value the variable
|
||||
will only be set if it was defined elsewhere (i.e. used
|
||||
within the configuration). It is highly recommended to
|
||||
always set this to true.
|
||||
|
||||
.. js:function:: TXN.unset_var(TXN, var)
|
||||
|
||||
@ -2513,7 +2517,7 @@ AppletHTTP class
|
||||
:param opaque data: The data which is stored in the transaction.
|
||||
:see: :js:func:`AppletHTTP.get_priv`
|
||||
|
||||
.. js:function:: AppletHTTP.set_var(applet, var, value)
|
||||
.. js:function:: AppletHTTP.set_var(applet, var, value[, ifexist])
|
||||
|
||||
Converts a Lua type in a HAProxy type and store it in a variable <var>.
|
||||
|
||||
@ -2521,6 +2525,10 @@ AppletHTTP class
|
||||
:param string var: The variable name according with the HAProxy variable syntax.
|
||||
:param type value: The value associated to the variable. The type ca be string or
|
||||
integer.
|
||||
:param boolean ifexist: If this parameter is set to a truthy value the variable
|
||||
will only be set if it was defined elsewhere (i.e. used
|
||||
within the configuration). It is highly recommended to
|
||||
always set this to true.
|
||||
:see: :js:func:`AppletHTTP.unset_var`
|
||||
:see: :js:func:`AppletHTTP.get_var`
|
||||
|
||||
@ -2624,7 +2632,7 @@ AppletTCP class
|
||||
:param opaque data: The data which is stored in the transaction.
|
||||
:see: :js:func:`AppletTCP.get_priv`
|
||||
|
||||
.. js:function:: AppletTCP.set_var(applet, var, value)
|
||||
.. js:function:: AppletTCP.set_var(applet, var, value[, ifexist])
|
||||
|
||||
Converts a Lua type in a HAProxy type and stores it in a variable <var>.
|
||||
|
||||
@ -2632,6 +2640,10 @@ AppletTCP class
|
||||
:param string var: The variable name according with the HAProxy variable syntax.
|
||||
:param type value: The value associated to the variable. The type can be string or
|
||||
integer.
|
||||
:param boolean ifexist: If this parameter is set to a truthy value the variable
|
||||
will only be set if it was defined elsewhere (i.e. used
|
||||
within the configuration). It is highly recommended to
|
||||
always set this to true.
|
||||
:see: :js:func:`AppletTCP.unset_var`
|
||||
:see: :js:func:`AppletTCP.get_var`
|
||||
|
||||
|
@ -10,3 +10,16 @@ core.register_service("set_var", "http", function(applet)
|
||||
applet:start_response()
|
||||
applet:send("")
|
||||
end)
|
||||
|
||||
core.register_service("set_var_ifexist", "http", function(applet)
|
||||
local var_name = applet.headers["var"][0]
|
||||
local result = applet:set_var(var_name, "value", true)
|
||||
if result then
|
||||
applet:set_status(202)
|
||||
else
|
||||
applet:set_status(400)
|
||||
end
|
||||
applet:add_header("echo", applet:get_var(var_name) or "(nil)")
|
||||
applet:start_response()
|
||||
applet:send("")
|
||||
end)
|
||||
|
@ -13,11 +13,20 @@ haproxy h1 -conf {
|
||||
bind "fd@${fe1}"
|
||||
|
||||
http-request use-service lua.set_var
|
||||
|
||||
frontend fe2
|
||||
mode http
|
||||
${no-htx} option http-use-htx
|
||||
bind "fd@${fe2}"
|
||||
|
||||
http-request set-header Dummy %[var(txn.fe2_foo)]
|
||||
|
||||
http-request use-service lua.set_var_ifexist
|
||||
} -start
|
||||
|
||||
client c0 -connect ${h1_fe1_sock} {
|
||||
txreq -url "/" \
|
||||
-hdr "Var: txn.foo"
|
||||
-hdr "Var: txn.fe1_foo"
|
||||
rxresp
|
||||
expect resp.status == 202
|
||||
expect resp.http.echo == "value"
|
||||
@ -27,3 +36,16 @@ client c0 -connect ${h1_fe1_sock} {
|
||||
expect resp.status == 400
|
||||
expect resp.http.echo == "(nil)"
|
||||
} -run
|
||||
|
||||
client c1 -connect ${h1_fe2_sock} {
|
||||
txreq -url "/" \
|
||||
-hdr "Var: txn.fe2_foo"
|
||||
rxresp
|
||||
expect resp.status == 202
|
||||
expect resp.http.echo == "value"
|
||||
txreq -url "/" \
|
||||
-hdr "Var: txn.fe2_bar"
|
||||
rxresp
|
||||
expect resp.status == 400
|
||||
expect resp.http.echo == "(nil)"
|
||||
} -run
|
||||
|
30
src/hlua.c
30
src/hlua.c
@ -3475,7 +3475,8 @@ __LJMP static int hlua_applet_tcp_set_var(lua_State *L)
|
||||
size_t len;
|
||||
struct sample smp;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "set_var"));
|
||||
if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
|
||||
WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
|
||||
|
||||
/* It is useles to retrieve the stream, but this function
|
||||
* runs only in a stream context.
|
||||
@ -3489,7 +3490,12 @@ __LJMP static int hlua_applet_tcp_set_var(lua_State *L)
|
||||
|
||||
/* Store the sample in a variable. */
|
||||
smp_set_owner(&smp, s->be, s->sess, s, 0);
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
|
||||
lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
|
||||
else
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3953,7 +3959,8 @@ __LJMP static int hlua_applet_http_set_var(lua_State *L)
|
||||
size_t len;
|
||||
struct sample smp;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "set_var"));
|
||||
if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
|
||||
WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
|
||||
|
||||
/* It is useles to retrieve the stream, but this function
|
||||
* runs only in a stream context.
|
||||
@ -3967,7 +3974,12 @@ __LJMP static int hlua_applet_http_set_var(lua_State *L)
|
||||
|
||||
/* Store the sample in a variable. */
|
||||
smp_set_owner(&smp, s->be, s->sess, s, 0);
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
|
||||
lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
|
||||
else
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -5040,7 +5052,8 @@ __LJMP static int hlua_set_var(lua_State *L)
|
||||
size_t len;
|
||||
struct sample smp;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "set_var"));
|
||||
if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
|
||||
WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
|
||||
|
||||
/* It is useles to retrieve the stream, but this function
|
||||
* runs only in a stream context.
|
||||
@ -5053,7 +5066,12 @@ __LJMP static int hlua_set_var(lua_State *L)
|
||||
|
||||
/* Store the sample in a variable. */
|
||||
smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
|
||||
lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
|
||||
else
|
||||
lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user