Hi guys,
Here is a funny config where I've encountered something unexpected.
The theme is URL rewriting (let's say for some API),
after getting the original URI, extracting fields from path, we want to
construct new path and save extracted fields into query args (we use
haproxy vars as storage)
1)
If you run the attached haproxy config as is, everything works as expected
curl -v localhost:8080/a/1/b/2 -o /dev/null 2>&1 |grep x-field
< x-field: /a/1/b/2?a=1&b=2
curl -v localhost:8080/a/1/d/2 -o /dev/null 2>&1 |grep x-field
< x-field: /a/1/d/2?a=1
2) However, since want to replace path as well, let's
uncomment first set-path from the config file
curl -v localhost:8080/a/1/b/2 -o /dev/null 2>&1 |grep x-field
< x-field: /a/1/b/2?a=1
Not expected!
If we move that set-path statement after set-query (Case 2) it starts
working fine again.
What's happening? Looks like set-var was lazily evaluated only after
we've used it in set-query lines guarded by acl.
3) If we replace both set-query lines with
http-request set-query "a=%[var(txn.a)]&b=%[var(txn.b)]"
It starts working again, but we'll always see "empty" b in the output:
curl -v localhost:8080/a/1/b2/2 -o /dev/null 2>&1 |grep x-field
< x-field: /x/y/z?a=1&b=
P.S.
For reference, here is the relevant config part:
http-request set-var(txn.a) path,field(3,/)
acl is_b path,field(4,/) -m str "b"
http-request set-var(txn.b) path,field(5,/) if is_b
# Case 1, we can't see b value if we set-path here
# http-request set-path /x/y/z
http-request set-query "a=%[var(txn.a)]" if !is_b
http-request set-query "a=%[var(txn.a)]&b=%[var(txn.b)]" if is_b
# Case 2, but we can see b value now
# http-request set-path /x/y/z
Best regards,
Adis
--
Adis Nezirovic
Software Engineer
HAProxy Technologies - Powering your uptime!
375 Totten Pond Road, Suite 302 | Waltham, MA 02451, US
+1 (844) 222-4340 | https://www.haproxy.com
global
log /dev/log local1
defaults
log global
timeout connect 5s
timeout client 10s
timeout server 10s
timeout http-request 1s
mode http
listen blah
bind 127.0.0.1:8080
http-request set-var(txn.a) path,field(3,/)
acl is_b path,field(4,/) -m str "b"
http-request set-var(txn.b) path,field(5,/) if is_b
# Case 1, we can't see b value if we set-path here
http-request set-path /x/y/z
#http-request set-query "a=%[var(txn.a)]" if !is_b
#http-request set-query "a=%[var(txn.a)]&b=%[var(txn.b)]" if is_b
http-request set-query "a=%[var(txn.a)]&b=%[var(txn.b)]"
# Case 2, but we can see b value now
#http-request set-path /x/y/z
http-request set-var(txn.url) url
http-response set-header X-Field %[var(txn.url)]
server srv1 haproxy.org:80