summaryrefslogtreecommitdiffstats
path: root/reg-tests/lua
diff options
context:
space:
mode:
Diffstat (limited to 'reg-tests/lua')
-rw-r--r--reg-tests/lua/bad_http_clt_req_duration.lua8
-rw-r--r--reg-tests/lua/bad_http_clt_req_duration.vtc76
-rw-r--r--reg-tests/lua/close_wait_lf.lua1
-rw-r--r--reg-tests/lua/close_wait_lf.vtc53
l---------reg-tests/lua/common.pem1
-rw-r--r--reg-tests/lua/h_txn_get_priv.lua15
-rw-r--r--reg-tests/lua/h_txn_get_priv.vtc33
-rw-r--r--reg-tests/lua/httpclient_action.lua8
-rw-r--r--reg-tests/lua/httpclient_action.vtc39
-rw-r--r--reg-tests/lua/lua_httpclient.lua49
-rw-r--r--reg-tests/lua/lua_httpclient.vtc68
-rw-r--r--reg-tests/lua/lua_socket.lua44
-rw-r--r--reg-tests/lua/lua_socket.vtc33
-rw-r--r--reg-tests/lua/set_var.lua25
-rw-r--r--reg-tests/lua/set_var.vtc83
-rw-r--r--reg-tests/lua/txn_get_priv-print_r.lua96
-rw-r--r--reg-tests/lua/txn_get_priv-thread.vtc69
-rw-r--r--reg-tests/lua/txn_get_priv.lua180
-rw-r--r--reg-tests/lua/txn_get_priv.vtc35
-rw-r--r--reg-tests/lua/wrong_types_usage.lua3
-rw-r--r--reg-tests/lua/wrong_types_usage.vtc77
21 files changed, 996 insertions, 0 deletions
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