From b46aad6df449445a9fc4aa7b32bd40005438e3f7 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 14:18:05 +0200 Subject: Adding upstream version 2.9.5. Signed-off-by: Daniel Baumann --- reg-tests/lua/bad_http_clt_req_duration.lua | 8 ++ reg-tests/lua/bad_http_clt_req_duration.vtc | 76 ++++++++++++ reg-tests/lua/close_wait_lf.lua | 1 + reg-tests/lua/close_wait_lf.vtc | 53 ++++++++ reg-tests/lua/common.pem | 1 + reg-tests/lua/h_txn_get_priv.lua | 15 +++ reg-tests/lua/h_txn_get_priv.vtc | 33 +++++ reg-tests/lua/httpclient_action.lua | 8 ++ reg-tests/lua/httpclient_action.vtc | 39 ++++++ reg-tests/lua/lua_httpclient.lua | 49 ++++++++ reg-tests/lua/lua_httpclient.vtc | 68 +++++++++++ reg-tests/lua/lua_socket.lua | 44 +++++++ reg-tests/lua/lua_socket.vtc | 33 +++++ reg-tests/lua/set_var.lua | 25 ++++ reg-tests/lua/set_var.vtc | 83 +++++++++++++ reg-tests/lua/txn_get_priv-print_r.lua | 96 +++++++++++++++ reg-tests/lua/txn_get_priv-thread.vtc | 69 +++++++++++ reg-tests/lua/txn_get_priv.lua | 180 ++++++++++++++++++++++++++++ reg-tests/lua/txn_get_priv.vtc | 35 ++++++ reg-tests/lua/wrong_types_usage.lua | 3 + reg-tests/lua/wrong_types_usage.vtc | 77 ++++++++++++ 21 files changed, 996 insertions(+) create mode 100644 reg-tests/lua/bad_http_clt_req_duration.lua create mode 100644 reg-tests/lua/bad_http_clt_req_duration.vtc create mode 100644 reg-tests/lua/close_wait_lf.lua create mode 100644 reg-tests/lua/close_wait_lf.vtc create mode 120000 reg-tests/lua/common.pem create mode 100644 reg-tests/lua/h_txn_get_priv.lua create mode 100644 reg-tests/lua/h_txn_get_priv.vtc create mode 100644 reg-tests/lua/httpclient_action.lua create mode 100644 reg-tests/lua/httpclient_action.vtc create mode 100644 reg-tests/lua/lua_httpclient.lua create mode 100644 reg-tests/lua/lua_httpclient.vtc create mode 100644 reg-tests/lua/lua_socket.lua create mode 100644 reg-tests/lua/lua_socket.vtc create mode 100644 reg-tests/lua/set_var.lua create mode 100644 reg-tests/lua/set_var.vtc create mode 100644 reg-tests/lua/txn_get_priv-print_r.lua create mode 100644 reg-tests/lua/txn_get_priv-thread.vtc create mode 100644 reg-tests/lua/txn_get_priv.lua create mode 100644 reg-tests/lua/txn_get_priv.vtc create mode 100644 reg-tests/lua/wrong_types_usage.lua create mode 100644 reg-tests/lua/wrong_types_usage.vtc (limited to 'reg-tests/lua') diff --git a/reg-tests/lua/bad_http_clt_req_duration.lua b/reg-tests/lua/bad_http_clt_req_duration.lua new file mode 100644 index 0000000..2c2ab1d --- /dev/null +++ b/reg-tests/lua/bad_http_clt_req_duration.lua @@ -0,0 +1,8 @@ +core.register_service("foo.http", "http", function(applet) + core.msleep(10) + applet:start_response() +end) + +core.register_service("foo.tcp", "tcp", function(applet) + applet:send("HTTP/1.1 200 OK\r\nTransfer-encoding: chunked\r\n\r\n0\r\n\r\n") +end) diff --git a/reg-tests/lua/bad_http_clt_req_duration.vtc b/reg-tests/lua/bad_http_clt_req_duration.vtc new file mode 100644 index 0000000..5cfdf1a --- /dev/null +++ b/reg-tests/lua/bad_http_clt_req_duration.vtc @@ -0,0 +1,76 @@ +# commit 7b6cc52784526c32efda44b873a4258d3ae0b8c7 +# BUG/MINOR: lua: Bad HTTP client request duration. +# +# HTTP LUA applet callback should not update the date on which the HTTP client requests +# arrive. This was done just after the LUA applet has completed its job. +# +# This patch simply removes the affected statement. The same fix has been applied +# to TCP LUA applet callback. +# +# To reproduce this issue, as reported by Patrick Hemmer, implement an HTTP LUA applet +# which sleeps a bit before replying: +# +# core.register_service("foo", "http", function(applet) +# core.msleep(100) +# applet:set_status(200) +# applet:start_response() +# end) +# +# This had as a consequence to log %TR field with approximately the same value as +# the LUA sleep time. + +varnishtest "LUA bug" +#REQUIRE_OPTIONS=LUA +#REGTEST_TYPE=bug + +feature ignore_unknown_macro + +syslog Slog { + recv info + expect ~ "[^:\\[ ]\\[[0-9]*\\]: Ta=[0-9]* Tc=[0-9]* Td=[0-9]* Th=[0-9]* Ti=[0-9]* Tq=[0-9]* TR=[0-9]* Tr=[0-9]* Tt=[0-9]* Tw=[0-9]*$" + + recv info + expect ~ "[^:\\[ ]\\[[0-9]*\\]: Tc=[0-9]* Td=[0-9]* Th=[0-9]* Tt=[0-9]* Tw=[0-9]*$" +} -start + +haproxy h1 -conf { + global + lua-load ${testdir}/bad_http_clt_req_duration.lua + + defaults + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + + frontend f1 + mode http + bind "fd@${f1}" + log ${Slog_addr}:${Slog_port} daemon + log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\ TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw + default_backend b1 + + backend b1 + mode http + http-request use-service lua.foo.http + + frontend f2 + mode tcp + bind "fd@${f2}" + log ${Slog_addr}:${Slog_port} daemon + log-format Tc=%Tc\ Td=%Td\ Th=%Th\ Tt=%Tt\ Tw=%Tw + + tcp-request inspect-delay 1s + tcp-request content use-service lua.foo.tcp +} -start + +client c1 -connect "${h1_f1_sock}" { + txreq + rxresp +} -run + +client c2 -connect "${h1_f2_sock}" { + txreq + rxresp +} -run + +syslog Slog -wait diff --git a/reg-tests/lua/close_wait_lf.lua b/reg-tests/lua/close_wait_lf.lua new file mode 100644 index 0000000..cc897e7 --- /dev/null +++ b/reg-tests/lua/close_wait_lf.lua @@ -0,0 +1 @@ +core.register_service("donothing", "http", function(applet) end) diff --git a/reg-tests/lua/close_wait_lf.vtc b/reg-tests/lua/close_wait_lf.vtc new file mode 100644 index 0000000..7bed3fd --- /dev/null +++ b/reg-tests/lua/close_wait_lf.vtc @@ -0,0 +1,53 @@ +# commit 70d318c +# BUG/MEDIUM: lua: possible CLOSE-WAIT state with '\n' headers +# +# The Lua parser doesn't takes in account end-of-headers containing +# only '\n'. It expects always '\r\n'. If a '\n' is processes the Lua +# parser considers it miss 1 byte, and wait indefinitely for new data. +# +# When the client reaches their timeout, it closes the connection. +# This close is not detected and the connection keep in CLOSE-WAIT +# state. +# +# I guess that this patch fix only a visible part of the problem. +# If the Lua HTTP parser wait for data, the timeout server or the +# connectio closed by the client may stop the applet. + +varnishtest "possible CLOSE-WAIT with '\n' headers" +#REQUIRE_OPTIONS=LUA +#REGTEST_TYPE=bug + +feature ignore_unknown_macro + +syslog Slog -level info -repeat 100 { + recv info + expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Ta=[0-9]* Tc=[0-9]* Td=[0-9]* Th=[0-9]* Ti=[0-9]* Tq=[0-9]* TR=[0-9]* Tr=[0-9]* Tt=[0-9]* Tw=[0-9]*" +} -start + +haproxy h1 -conf { + defaults + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + + global + lua-load ${testdir}/close_wait_lf.lua + + frontend frt + log ${Slog_addr}:${Slog_port} local0 debug err + log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\ TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw + mode http + bind "fd@${frt}" + http-request use-service lua.donothing +} -start + + +client c1 -connect ${h1_frt_sock} -repeat 100 { + send "GET / HTTP/1.1\n\n" +} -run + +syslog Slog -wait + +shell { + ss -pt | grep CLOSE-WAIT.*haproxy.*pid=${h1_pid} + exit $((!$?)) +} diff --git a/reg-tests/lua/common.pem b/reg-tests/lua/common.pem new file mode 120000 index 0000000..a4433d5 --- /dev/null +++ b/reg-tests/lua/common.pem @@ -0,0 +1 @@ +../ssl/common.pem \ No newline at end of file diff --git a/reg-tests/lua/h_txn_get_priv.lua b/reg-tests/lua/h_txn_get_priv.lua new file mode 100644 index 0000000..999ea88 --- /dev/null +++ b/reg-tests/lua/h_txn_get_priv.lua @@ -0,0 +1,15 @@ +core.register_action("bug", { "http-res" }, function(txn) + data = txn:get_priv() + if not data then + data = 0 + end + data = data + 1 + print(string.format("set to %d", data)) + txn.http:res_set_status(200 + data) + txn:set_priv(data) +end) + +core.register_service("fakeserv", "http", function(applet) + applet:set_status(200) + applet:start_response() +end) diff --git a/reg-tests/lua/h_txn_get_priv.vtc b/reg-tests/lua/h_txn_get_priv.vtc new file mode 100644 index 0000000..bd8c069 --- /dev/null +++ b/reg-tests/lua/h_txn_get_priv.vtc @@ -0,0 +1,33 @@ +varnishtest "Lua: txn:get_priv() scope" +#REQUIRE_OPTIONS=LUA + +feature ignore_unknown_macro + +haproxy h1 -conf { + global + lua-load ${testdir}/h_txn_get_priv.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + http-response lua.bug + + backend b1 + mode http + http-request use-service lua.fakeserv +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq -url "/" + rxresp + expect resp.status == 201 + txreq -url "/" + rxresp + expect resp.status == 201 +} + +client c0 -start + +client c0 -wait diff --git a/reg-tests/lua/httpclient_action.lua b/reg-tests/lua/httpclient_action.lua new file mode 100644 index 0000000..9a7209c --- /dev/null +++ b/reg-tests/lua/httpclient_action.lua @@ -0,0 +1,8 @@ +function test() + local httpclient = core.httpclient() + local response = httpclient:get{url="http://127.0.0.1", headers={ [ "Host" ] = { "localhost" } }} + +end + + +core.register_action("test", {"tcp-req"}, test, 0) diff --git a/reg-tests/lua/httpclient_action.vtc b/reg-tests/lua/httpclient_action.vtc new file mode 100644 index 0000000..11c7d62 --- /dev/null +++ b/reg-tests/lua/httpclient_action.vtc @@ -0,0 +1,39 @@ +varnishtest "Lua: test the httpclient when the lua action timeout" +# +# Start an httpclient from "lua.test" whose lua task will expire before the +# httpclient is ended. + + +feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev7)'" +feature ignore_unknown_macro + +#REQUIRE_OPTIONS=LUA + +haproxy h1 -conf { + + global + lua-load ${testdir}/httpclient_action.lua + defaults + mode tcp + timeout http-request 10s + timeout queue 1m + timeout connect 10s + timeout client 1m + timeout server 1m + timeout check 10s + + listen li1 + mode http + bind "fd@${fe1}" + tcp-request inspect-delay 10ms + tcp-request content lua.test + http-request return status 503 + +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq + rxresp + expect resp.status == 503 +} -run + diff --git a/reg-tests/lua/lua_httpclient.lua b/reg-tests/lua/lua_httpclient.lua new file mode 100644 index 0000000..b5a5180 --- /dev/null +++ b/reg-tests/lua/lua_httpclient.lua @@ -0,0 +1,49 @@ + +local vtc_port = 0 +local vtc_port2 = 0 +local vtc_port3 = 0 + +core.register_service("fakeserv", "http", function(applet) + vtc_port = applet.headers["vtcport"][0] + vtc_port2 = applet.headers["vtcport2"][0] + vtc_port3 = applet.headers["vtcport3"][0] + core.Info("APPLET START") + local response = "OK" + applet:add_header("Server", "haproxy/webstats") + applet:add_header("Content-Length", string.len(response)) + applet:add_header("Content-Type", "text/html") + applet:start_response() + applet:send(response) + core.Info("APPLET DONE") +end) + +local function cron() + -- wait for until the correct port is set through the c0 request.. + while vtc_port == 0 do + core.msleep(1) + end + core.Debug('CRON port:' .. vtc_port) + + local body = "" + + for i = 0, 2000 do + body = body .. i .. ' ABCDEFGHIJKLMNOPQRSTUVWXYZ\n' + end + core.Info("First httpclient request") + local httpclient = core.httpclient() + local response = httpclient:post{url="http://127.0.0.1:" .. vtc_port, body=body} + core.Info("Received: " .. response.body) + + body = response.body + + core.Info("Second httpclient request") + local httpclient2 = core.httpclient() + local response2 = httpclient2:post{url="http://127.0.0.1:" .. vtc_port2, body=body} + + core.Info("Third httpclient request") + local httpclient3 = core.httpclient() + local response3 = httpclient3:get{url="http://127.0.0.1", dst = vtc_port3, headers={ [ "Host" ] = { "foobar.haproxy.local" } }} + +end + +core.register_task(cron) diff --git a/reg-tests/lua/lua_httpclient.vtc b/reg-tests/lua/lua_httpclient.vtc new file mode 100644 index 0000000..0a27493 --- /dev/null +++ b/reg-tests/lua/lua_httpclient.vtc @@ -0,0 +1,68 @@ +varnishtest "Lua: check httpclient functionality from a lua-task" + +# A request if first made with c0 with the port of s1 and s2 so the httpclient +# can generate its URI with it. +# +# This reg-test sends a payload with the httpclient to s1, s1 returns another +# payload. The 2nd lua httpclient sends back the payload from s1 to s2. +# + +feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev7)'" +feature ignore_unknown_macro + +#REQUIRE_OPTIONS=LUA + +server s1 { + rxreq + txresp -bodylen 54000 + expect req.body ~ ".*0 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*" + expect req.body ~ ".*500 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*" + expect req.body ~ ".*1000 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*" + expect req.body ~ ".*1500 ABCDEFGHIJKLMNOPQRSTUVWXYZ.*" + expect req.body ~ ".*2000 ABCDEFGHIJKLMNOPQRSTUVWXYZ" +} -start + +server s2 { + rxreq + txresp + expect req.bodylen == 54000 +} -start + +server s3 { + rxreq + txresp -bodylen 54000 + expect req.method == "GET" + expect req.http.host == "foobar.haproxy.local" +} -start + + +haproxy h1 -conf { + global + lua-load ${testdir}/lua_httpclient.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + backend b1 + mode http + http-request use-service lua.fakeserv + + listen li1 + mode http + bind unix@${tmpdir}/srv3 + server srv3 ${s3_addr}:${s3_port} + +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq -url "/" -hdr "vtcport: ${s1_port}" -hdr "vtcport2: ${s2_port}" -hdr "vtcport3: unix@${tmpdir}/srv3" + rxresp + expect resp.status == 200 +} -run + + +server s1 -wait +server s2 -wait +server s3 -wait diff --git a/reg-tests/lua/lua_socket.lua b/reg-tests/lua/lua_socket.lua new file mode 100644 index 0000000..3ad14fe --- /dev/null +++ b/reg-tests/lua/lua_socket.lua @@ -0,0 +1,44 @@ + +local vtc_port = 0 + +core.register_service("fakeserv", "http", function(applet) + vtc_port = applet.headers["vtcport"][0] + core.Info("APPLET START") + local response = "OK" + applet:add_header("Server", "haproxy/webstats") + applet:add_header("Content-Length", string.len(response)) + applet:add_header("Content-Type", "text/html") + applet:start_response() + applet:send(response) + core.Info("APPLET DONE") +end) + +local function cron() + -- wait for until the correct port is set through the c0 request.. + while vtc_port == 0 do + core.msleep(1) + end + core.Debug('CRON port:' .. vtc_port) + + local socket = core.tcp() + local success = socket:connect("127.0.0.1", vtc_port) + core.Info("SOCKET MADE ".. (success or "??")) + if success ~= 1 then + core.Info("CONNECT SOCKET FAILED?") + return + end + local request = "GET / HTTP/1.1\r\n\r\n" + core.Info("SENDING REQUEST") + socket:send(request) + local result = "" + repeat + core.Info("4") + local d = socket:receive("*a") + if d ~= nil then + result = result .. d + end + until d == nil or d == 0 + core.Info("Received: "..result) +end + +core.register_task(cron) \ No newline at end of file diff --git a/reg-tests/lua/lua_socket.vtc b/reg-tests/lua/lua_socket.vtc new file mode 100644 index 0000000..83e06a6 --- /dev/null +++ b/reg-tests/lua/lua_socket.vtc @@ -0,0 +1,33 @@ +varnishtest "Lua: check socket functionality from a lua-task" +feature ignore_unknown_macro + +#REQUIRE_OPTIONS=LUA + +server s1 { + rxreq + txresp -bodylen 20 +} -start + +haproxy h1 -conf { + global + lua-load ${testdir}/lua_socket.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + backend b1 + mode http + http-request use-service lua.fakeserv + +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq -url "/" -hdr "vtcport: ${s1_port}" + rxresp + expect resp.status == 200 +} -run + + +server s1 -wait diff --git a/reg-tests/lua/set_var.lua b/reg-tests/lua/set_var.lua new file mode 100644 index 0000000..f4d5e7a --- /dev/null +++ b/reg-tests/lua/set_var.lua @@ -0,0 +1,25 @@ +core.register_service("set_var", "http", function(applet) + local var_name = applet.headers["var"][0] + local result = applet:set_var(var_name, "value") + 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) + +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) diff --git a/reg-tests/lua/set_var.vtc b/reg-tests/lua/set_var.vtc new file mode 100644 index 0000000..0c8a4b1 --- /dev/null +++ b/reg-tests/lua/set_var.vtc @@ -0,0 +1,83 @@ +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 diff --git a/reg-tests/lua/txn_get_priv-print_r.lua b/reg-tests/lua/txn_get_priv-print_r.lua new file mode 100644 index 0000000..185614f --- /dev/null +++ b/reg-tests/lua/txn_get_priv-print_r.lua @@ -0,0 +1,96 @@ +-- Copyright 2016 Thierry Fournier + +function color(index, str) + return "\x1b[" .. index .. "m" .. str .. "\x1b[00m" +end + +function nocolor(index, str) + return str +end + +function sp(count) + local spaces = "" + while count > 0 do + spaces = spaces .. " " + count = count - 1 + end + return spaces +end + +function escape(str) + local s = "" + for i = 1, #str do + local c = str:sub(i,i) + local ascii = string.byte(c, 1) + if ascii > 126 or ascii < 20 then + s = s .. string.format("\\x%02x", ascii) + else + s = s .. c + end + end + return s +end + +function print_rr(p, indent, c, wr, hist) + local i = 0 + local nl = "" + + if type(p) == "table" then + wr(c("33", "(table)") .. " " .. c("36", tostring(p)) .. " [") + + for idx, value in ipairs(hist) do + if value == p then + wr(" " .. c("35", "/* recursion */") .. " ]") + return + end + end + hist[indent + 1] = p + + mt = getmetatable(p) + if mt ~= nil then + wr("\n" .. sp(indent+1) .. c("31", "METATABLE") .. ": ") + print_rr(mt, indent+1, c, wr, hist) + end + + for k,v in pairs(p) do + if i > 0 then + nl = "\n" + else + wr("\n") + end + wr(nl .. sp(indent+1)) + if type(k) == "number" then + wr(c("32", tostring(k))) + else + wr("\"" .. c("32", escape(tostring(k))) .. "\"") + end + wr(": ") + print_rr(v, indent+1, c, wr, hist) + i = i + 1 + end + if i == 0 then + wr(" " .. c("35", "/* empty */") .. " ]") + else + wr("\n" .. sp(indent) .. "]") + end + + hist[indent + 1] = nil + + elseif type(p) == "string" then + wr(c("33", "(string)") .. " \"" .. c("36", escape(p)) .. "\"") + else + wr(c("33", "(" .. type(p) .. ")") .. " " .. c("36", tostring(p))) + end +end + +function print_r(p, col, wr) + if col == nil then col = true end + if wr == nil then wr = function(msg) io.stdout:write(msg) end end + local hist = {} + if col == true then + print_rr(p, 0, color, wr, hist) + else + print_rr(p, 0, nocolor, wr, hist) + end + wr("\n") +end diff --git a/reg-tests/lua/txn_get_priv-thread.vtc b/reg-tests/lua/txn_get_priv-thread.vtc new file mode 100644 index 0000000..9538363 --- /dev/null +++ b/reg-tests/lua/txn_get_priv-thread.vtc @@ -0,0 +1,69 @@ +varnishtest "Lua: txn:get_priv() scope" +#REQUIRE_OPTIONS=LUA,OPENSSL +#REQUIRE_VERSION=2.4 +#REGTEST_TYPE=bug + +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 + + lua-load-per-thread ${testdir}/txn_get_priv.lua + lua-load-per-thread ${testdir}/txn_get_priv-print_r.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + frontend fe2 + mode http + bind ":8443" ssl crt ${testdir}/common.pem + stats enable + stats uri / + + backend b1 + mode http + http-request use-service lua.fakeserv +} -start + +client c0 -repeat 4 -connect ${h1_fe1_sock} { + txreq -url "/0" + rxresp + expect resp.status == 200 + txreq -url "/0" + rxresp + expect resp.status == 200 +} -run + +client c1 -repeat 4 -connect ${h1_fe1_sock} { + txreq -url "/1" + rxresp + expect resp.status == 200 + txreq -url "/1" + rxresp + expect resp.status == 200 +} -run + +client c2 -repeat 4 -connect ${h1_fe1_sock} { + txreq -url "/2" + rxresp + expect resp.status == 200 + txreq -url "/2" + rxresp + expect resp.status == 200 +} -run + +client c3 -repeat 4 -connect ${h1_fe1_sock} { + txreq -url "/3" + rxresp + expect resp.status == 200 + txreq -url "/3" + rxresp + expect resp.status == 200 +} -run + diff --git a/reg-tests/lua/txn_get_priv.lua b/reg-tests/lua/txn_get_priv.lua new file mode 100644 index 0000000..dd5623c --- /dev/null +++ b/reg-tests/lua/txn_get_priv.lua @@ -0,0 +1,180 @@ +Luacurl = {} +Luacurl.__index = Luacurl +setmetatable(Luacurl, { + __call = function (cls, ...) + return cls.new(...) + end, +}) +function Luacurl.new(server, port, ssl) + local self = setmetatable({}, Luacurl) + self.sockconnected = false + self.server = server + self.port = port + self.ssl = ssl + self.cookies = {} + return self +end + +function Luacurl:get(method,url,headers,data) + core.Info("MAKING SOCKET") + if self.sockconnected == false then + self.sock = core.tcp() + if self.ssl then + local r = self.sock:connect_ssl(self.server,self.port) + else + local r = self.sock:connect(self.server,self.port) + end + self.sockconnected = true + end + core.Info("SOCKET MADE") + local request = method.." "..url.." HTTP/1.1" + if data ~= nil then + request = request .. "\r\nContent-Length: "..string.len(data) + end + if headers ~= null then + for h,v in pairs(headers) do + request = request .. "\r\n"..h..": "..v + end + end + cookstring = "" + for cook,cookval in pairs(self.cookies) do + cookstring = cookstring .. cook.."="..cookval.."; " + end + if string.len(cookstring) > 0 then + request = request .. "\r\nCookie: "..cookstring + end + + request = request .. "\r\n\r\n" + if data and string.len(data) > 0 then + request = request .. data + end +--print(request) + core.Info("SENDING REQUEST") + self.sock:send(request) + +-- core.Info("PROCESSING RESPONSE") + return processhttpresponse(self.sock) +end + +function processhttpresponse(socket) + local res = {} +core.Info("1") + res.status = socket:receive("*l") +core.Info("2") + + if res.status == nil then + core.Info(" processhttpresponse RECEIVING status: NIL") + return res + end + core.Info(" processhttpresponse RECEIVING status:"..res.status) + res.headers = {} + res.headerslist = {} + repeat +core.Info("3") + local header = socket:receive("*l") + if header == nil then + return "error" + end + local valuestart = header:find(":") + if valuestart ~= nil then + local head = header:sub(1,valuestart-1) + local value = header:sub(valuestart+2) + table.insert(res.headerslist, {head,value}) + res.headers[head] = value + end + until header == "" + local bodydone = false + if res.headers["Connection"] ~= nil and res.headers["Connection"] == "close" then +-- core.Info("luacurl processresponse with connection:close") + res.body = "" + repeat +core.Info("4") + local d = socket:receive("*a") + if d ~= nil then + res.body = res.body .. d + end + until d == nil or d == 0 + bodydone = true + end + if bodydone == false and res.headers["Content-Length"] ~= nil then + res.contentlength = tonumber(res.headers["Content-Length"]) + if res.contentlength == nil then + core.Warning("res.contentlength ~NIL = "..res.headers["Content-Length"]) + end +-- core.Info("luacur, contentlength="..res.contentlength) + res.body = "" + repeat + local d = socket:receive(res.contentlength) + if d == nil then +-- core.Info("luacurl, ERROR?: received NIL, expecting "..res.contentlength.." bytes only got "..string.len(res.body).." sofar") + return + else + res.body = res.body..d +-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body)) + if string.len(res.body) >= res.contentlength then +-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body)) + break + end + end +-- core.Info("processhttpresponse, Loopy, get more body data! to receive complete contentlenght") + until false + end + if res.headers["Transfer-Encoding"] ~= nil and res.headers["Transfer-Encoding"] == "chunked" then + local chunksize = 0 + res.contentlength = 0 + res.body = "" + repeat +core.Info("5") + local chunksizestr = socket:receive("*l") + if chunksizestr == nil then + break + end + chunksize = tonumber("0x"..chunksizestr) + if chunksize ~= nil then + res.contentlength = res.contentlength + chunksize + if chunksize ~= 0 then + local chunk = socket:receive(chunksize) + res.body = res.body .. chunk + chunksizestr = socket:receive("*l") + if chunksizestr ~= "" then + return "ERROR Chunk-end expected." + end + end + else + break + end + until false + end +core.Info("6") + return res +end + +function Luacurl:close() + if self.sockconnected == true then + self.sock:close() + self.sockconnected = false + end +end + +function print_r_string(object) + local res = "" + print_r(object,false,function(x) res = res .. x end) + return res +end + +core.register_service("fakeserv", "http", function(applet) + core.Info("APPLET START") + local mc = Luacurl("127.0.0.1",8443, true) + local headers = {} + local body = "" + core.Info("APPLET GET") + local res = mc:get("GET", "/", headers, body) + core.Info("APPLET GET done") + local response = print_r_string(res) + applet:add_header("Server", "haproxy/webstats") + applet:add_header("Content-Length", string.len(response)) + applet:add_header("Content-Type", "text/html") + applet:start_response() + applet:send(response) + core.Info("APPLET DONE") +end) diff --git a/reg-tests/lua/txn_get_priv.vtc b/reg-tests/lua/txn_get_priv.vtc new file mode 100644 index 0000000..71e7bb5 --- /dev/null +++ b/reg-tests/lua/txn_get_priv.vtc @@ -0,0 +1,35 @@ +varnishtest "Lua: txn:get_priv() scope" +#REQUIRE_OPTIONS=LUA,OPENSSL +#REGTEST_TYPE=bug + +feature ignore_unknown_macro + +haproxy h1 -conf { + global + lua-load ${testdir}/txn_get_priv.lua + lua-load ${testdir}/txn_get_priv-print_r.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + frontend fe2 + mode http + bind ":8443" ssl crt ${testdir}/common.pem + stats enable + stats uri / + + backend b1 + mode http + http-request use-service lua.fakeserv +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq -url "/" + rxresp + expect resp.status == 200 + txreq -url "/" + rxresp + expect resp.status == 200 +} -run diff --git a/reg-tests/lua/wrong_types_usage.lua b/reg-tests/lua/wrong_types_usage.lua new file mode 100644 index 0000000..d2401fa --- /dev/null +++ b/reg-tests/lua/wrong_types_usage.lua @@ -0,0 +1,3 @@ +core.register_action("foo", { "http-req" }, function(txn) + txn.sc:ipmask(txn.f:src(), 24, 112) +end) diff --git a/reg-tests/lua/wrong_types_usage.vtc b/reg-tests/lua/wrong_types_usage.vtc new file mode 100644 index 0000000..ed76579 --- /dev/null +++ b/reg-tests/lua/wrong_types_usage.vtc @@ -0,0 +1,77 @@ +# commit f874a83 +# BUG/MINOR: lua: Segfaults with wrong usage of types. +# +# Patrick reported that this simple configuration made haproxy segfaults: +# +# global +# lua-load /tmp/haproxy.lua +# +# frontend f1 +# mode http +# bind :8000 +# default_backend b1 +# +# http-request lua.foo +# +# backend b1 +# mode http +# server s1 127.0.0.1:8080 +# +# with this '/tmp/haproxy.lua' script: +# +# core.register_action("foo", { "http-req" }, function(txn) +# txn.sc:ipmask(txn.f:src(), 24, 112) +# end) +# +# This is due to missing initialization of the array of arguments +# passed to hlua_lua2arg_check() which makes it enter code with +# corrupted arguments. +# +# Thanks a lot to Patrick Hemmer for having reported this issue. + + +varnishtest "Basic LUA test h00000" +#REQUIRE_OPTIONS=LUA +#REGTEST_TYPE=bug + +feature ignore_unknown_macro + +server s1 -repeat 2 { + rxreq + txresp +} -start + +haproxy h1 -conf { + global + lua-load ${testdir}/wrong_types_usage.lua + + frontend fe1 + mode http + bind "fd@${fe1}" + default_backend b1 + + http-request lua.foo + + backend b1 + mode http + server s1 ${s1_addr}:${s1_port} + +} -start + +client c0 -connect ${h1_fe1_sock} { + txreq -url "/foo" + rxresp + expect resp.status == 200 +} + +client c1 -connect ${h1_fe1_sock} { + txreq -url "/foo" + rxresp + expect resp.status == 200 +} + +client c0 -start +client c1 -start + +client c0 -wait +client c1 -wait -- cgit v1.2.3