mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-15 16:04:37 +00:00
3a4bedccc6
The global table of known variables names can only grow and was designed
for static names that are registered at boot. Nowadays it's possible to
set dynamic variable names from Lua or from the CLI, which causes a real
problem that was partially addressed in 2.2 with commit 4e172c93f
("MEDIUM: lua: Add `ifexist` parameter to `set_var`"). Please see github
issue #624 for more context.
This patch simplifies all this by removing the need for a central
registry of known names, and storing 64-bit hashes instead. This is
highly sufficient given the low number of variables in each context.
The hash is calculated using XXH64() which is bijective over the 64-bit
space thus is guaranteed collision-free for 1..8 chars. Above that the
risk remains around 1/2^64 per extra 8 chars so in practice this is
highly sufficient for our usage. A random seed is used at boot to seed
the hash so that it's not attackable from Lua for example.
There's one particular nit though. The "ifexist" hack mentioned above
is now limited to variables of scope "proc" only, and will only match
variables that were already created or declared, but will now verify
the scope as well. This may affect some bogus Lua scripts and SPOE
agents which used to accidentally work because a similarly named
variable used to exist in a different scope. These ones may need to be
fixed to comply with the doc.
Now we can sum up the situation as this one:
- ephemeral variables (scopes sess, txn, req, res) will always be
usable, regardless of any prior declaration. This effectively
addresses the most problematic change from the commit above that
in order to work well could have required some script auditing ;
- process-wide variables (scope proc) that are mentioned in the
configuration, referenced in a "register-var-names" SPOE directive,
or created via "set-var" in the global section or the CLI, are
permanent and will always accept to be set, with or without the
"ifexist" restriction (SPOE uses this internally as well).
- process-wide variables (scope proc) that are only created via a
set-var() tcp/http action, via Lua's set_var() calls, or via an
SPOE with the "force-set-var" directive), will not be permanent
but will always accept to be replaced once they are created, even
if "ifexist" is present
- process-wide variables (scope proc) that do not exist will only
support being created via the set-var() tcp/http action, Lua's
set_var() calls without "ifexist", or an SPOE declared with
"force-set-var".
This means that non-proc variables do not care about "ifexist" nor
prior declaration, and that using "ifexist" should most often be
reliable in Lua and that SPOE should most often work without any
prior declaration. It may be doable to turn "ifexist" to 1 by default
in Lua to further ease the transition. Note: regtests were adjusted.
Cc: Tim Düsterhus <tim@bastelstu.be>
84 lines
1.9 KiB
Plaintext
84 lines
1.9 KiB
Plaintext
varnishtest "Lua: set_var"
|
|
#REQUIRE_VERSION=2.2
|
|
#REQUIRE_OPTIONS=LUA
|
|
|
|
feature ignore_unknown_macro
|
|
|
|
haproxy h1 -conf {
|
|
global
|
|
# WT: limit false-positives causing "HTTP header incomplete" due to
|
|
# idle server connections being randomly used and randomly expiring
|
|
# under us.
|
|
tune.idle-pool.shared off
|
|
|
|
global
|
|
lua-load ${testdir}/set_var.lua
|
|
|
|
frontend fe1
|
|
mode http
|
|
bind "fd@${fe1}"
|
|
|
|
http-request use-service lua.set_var
|
|
|
|
frontend fe2
|
|
mode http
|
|
bind "fd@${fe2}"
|
|
# just make sure the variable exists
|
|
http-request set-header Dummy %[var(proc.fe2_foo)]
|
|
|
|
http-request use-service lua.set_var_ifexist
|
|
} -start
|
|
|
|
client c0 -connect ${h1_fe1_sock} {
|
|
# create var
|
|
txreq -url "/" \
|
|
-hdr "Var: txn.fe1_foo"
|
|
rxresp
|
|
expect resp.status == 202
|
|
expect resp.http.echo == "value"
|
|
|
|
# rewrite var
|
|
txreq -url "/" \
|
|
-hdr "Var: txn.fe1_foo"
|
|
rxresp
|
|
expect resp.status == 202
|
|
expect resp.http.echo == "value"
|
|
|
|
# create var under scope "proc"
|
|
txreq -url "/" \
|
|
-hdr "Var: proc.fe1_foo"
|
|
rxresp
|
|
expect resp.status == 202
|
|
expect resp.http.echo == "value"
|
|
|
|
# fail to create bad scope
|
|
txreq -url "/" \
|
|
-hdr "Var: invalid.var"
|
|
rxresp
|
|
expect resp.status == 400
|
|
expect resp.http.echo == "(nil)"
|
|
} -run
|
|
|
|
client c1 -connect ${h1_fe2_sock} {
|
|
# this one exists in the conf, it must succeed
|
|
txreq -url "/" \
|
|
-hdr "Var: proc.fe2_foo"
|
|
rxresp
|
|
expect resp.status == 202
|
|
expect resp.http.echo == "value"
|
|
|
|
# this one does not exist in the conf, it must fail
|
|
txreq -url "/" \
|
|
-hdr "Var: proc.fe2_bar"
|
|
rxresp
|
|
expect resp.status == 400
|
|
expect resp.http.echo == "(nil)"
|
|
|
|
# this one is under txn, it must succeed
|
|
txreq -url "/" \
|
|
-hdr "Var: txn.fe2_foo"
|
|
rxresp
|
|
expect resp.status == 202
|
|
expect resp.http.echo == "value"
|
|
} -run
|