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

Reply via email to