Take action based on json key's value from payload data

We are trying to, temporarily, route traffic at different backends based on a key’s value in requests body, haproxy.conf and lua script are following.

The problem is that payload could not be processed by json package used. Error message:

Lua sample-fetch 'choose_backend': runtime error: /etc/haproxy/json.lua:185: unexpected character 'P' at line 1 col 1 from [C] global 'error', /etc/haproxy/json.lua:185 upvalue 'decode_error', /etc/haproxy/json.lua:383 upvalue 'parse', /etc/haproxy/json.lua:391 field 'decode', /etc/haproxy/test.lua:4 C function line 2.

We tried to print payload (with both print() and trx.log()) or find exact txn.req:dup() returned value structure in documentation but both could not be found anywhere. Any guidance on how to print payload or if there is any other error?

haproxy.cfg

global
  log /dev/log    local0
  log /dev/log    local1 notice debug
  chroot /var/lib/haproxy
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  stats timeout 30s
  user haproxy
  group haproxy
  daemon
  lua-load /etc/haproxy/test.lua

defaults
  log     global
  mode    http
  option  httplog
  option  dontlognull
  timeout connect 5000
  timeout client  50000
  timeout server  50000

frontend http-in
  bind *:80
  option http-buffer-request
  use_backend %[lua.choose_backend]

backend proxy_1_backend
  option httpchk GET / 
  server ser1 1.1.1.1:80 maxconn 45 check

backend proxy_2_backend
  option httpchk GET /
  server ser2 2.2.2.2:80 maxconn 45 check

test.lua

-- load json library from https://github.com/rxi/json.lua 
json = loadfile("/etc/haproxy/json.lua")()                
core.register_fetches("choose_backend", function(txn)     
-- get request's payload                                  
local payload = txn.req:dup()                             
-- transform json to lua table                            
local request_json = json.decode(payload)                 
if request_json.test_key == 111 then               
  return "proxy_1_backend"                                
else                                                      
  return "proxy_2_backend"                                
end                                                       
end)

test requests

# Request should be forwarded to proxy_2_backend                                
curl -vvv -XPOST -d '{"test_key": 222, "someother_key": 222}' http://localhost  
# Request should be forwarded to proxy_1_backend                                
curl -vvv -XPOST -d '{"test_key": 111, "someother_key": 222}' http://localhost  

With “core.Info(payload)” you would have seen you’re trying to decode a string like “POST / HTTP/1.1\r\n” followed by a number of headers before getting to the JSON part. You should at least skip the headers by skipping to the first double CRLF.

local request_json = json.decode(string.sub(payload,string.find(payload,"\r\n\r\n")+4))

1 Like

Thanks for both! Request printed and payload has only json file!