blob: 88694395cb3fed202328e7a47c47c70336dd6165 [file] [log] [blame] [raw]
# vim:set ft= ts=4 sw=4 et fdm=marker:
use lib 'lib';
use Test::Nginx::Socket::Lua;
#worker_connections(1014);
#no_nginx_manager();
#log_level('warn');
#master_on();
repeat_each(2);
plan tests => repeat_each() * (blocks() * 2 + 9);
#no_diff();
#no_long_string();
run_tests();
__DATA__
=== TEST 1: basic print
--- config
location /lua {
# NOTE: the newline escape sequence must be double-escaped, as nginx config
# parser will unescape first!
rewrite_by_lua 'ngx.print("Hello, Lua!\\n")';
content_by_lua return;
#content_by_lua 'ngx.say("Hi")';
}
--- request
GET /lua
--- response_body
Hello, Lua!
=== TEST 2: basic say
--- config
location /say {
# NOTE: the newline escape sequence must be double-escaped, as nginx config
# parser will unescape first!
rewrite_by_lua '
ngx.say("Hello, Lua!")
ngx.say("Yay! ", 123)';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /say
--- response_body
Hello, Lua!
Yay! 123
=== TEST 3: no ngx.echo
--- config
location /lua {
rewrite_by_lua 'ngx.echo("Hello, Lua!\\n")';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body_like: 500 Internal Server Error
--- error_code: 500
=== TEST 4: variable
--- config
location /lua {
# NOTE: the newline escape sequence must be double-escaped, as nginx config
# parser will unescape first!
rewrite_by_lua 'v = ngx.var["request_uri"] ngx.print("request_uri: ", v, "\\n")';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua?a=1&b=2
--- response_body
request_uri: /lua?a=1&b=2
=== TEST 5: variable (file)
--- config
location /lua {
rewrite_by_lua_file html/test.lua;
content_by_lua 'ngx.exit(ngx.OK)';
}
--- user_files
>>> test.lua
v = ngx.var["request_uri"]
ngx.print("request_uri: ", v, "\n")
--- request
GET /lua?a=1&b=2
--- response_body
request_uri: /lua?a=1&b=2
=== TEST 6: calc expression
--- config
location /lua {
rewrite_by_lua_file html/calc.lua;
content_by_lua 'ngx.exit(ngx.OK)';
}
--- user_files
>>> calc.lua
local function uri_unescape(uri)
local function convert(hex)
return string.char(tonumber("0x"..hex))
end
local s = string.gsub(uri, "%%([0-9a-fA-F][0-9a-fA-F])", convert)
return s
end
local function eval_exp(str)
return loadstring("return "..str)()
end
local exp_str = ngx.var["arg_exp"]
-- print("exp: '", exp_str, "'\n")
local status, res
status, res = pcall(uri_unescape, exp_str)
if not status then
ngx.print("error: ", res, "\n")
return
end
status, res = pcall(eval_exp, res)
if status then
ngx.print("result: ", res, "\n")
else
ngx.print("error: ", res, "\n")
end
--- request
GET /lua?exp=1%2B2*math.sin(3)%2Fmath.exp(4)-math.sqrt(2)
--- response_body
result: -0.4090441561579
=== TEST 7: read $arg_xxx
--- config
location = /lua {
rewrite_by_lua 'who = ngx.var.arg_who
ngx.print("Hello, ", who, "!")';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua?who=agentzh
--- response_body chomp
Hello, agentzh!
=== TEST 8: capture location
--- config
location /other {
echo "hello, world";
}
location /lua {
rewrite_by_lua '
res = ngx.location.capture("/other")
ngx.print("status=", res.status, " ")
ngx.print("body=", res.body)
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body
status=200 body=hello, world
=== TEST 9: capture non-existed location
--- config
location /lua {
rewrite_by_lua 'res = ngx.location.capture("/other"); ngx.print("status=", res.status)';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body: status=404
=== TEST 10: invalid capture location (not as expected...)
--- config
location /lua {
rewrite_by_lua 'res = ngx.location.capture("*(#*"); ngx.say("res=", res.status)';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body
res=404
=== TEST 11: nil is "nil"
--- config
location /lua {
rewrite_by_lua 'ngx.say(nil)';
content_by_lua return;
}
--- request
GET /lua
--- response_body
nil
=== TEST 12: write boolean
--- config
location /lua {
rewrite_by_lua 'ngx.say(true, " ", false)';
content_by_lua return;
}
--- request
GET /lua
--- response_body
true false
=== TEST 13: bad argument type to ngx.location.capture
--- config
location /lua {
rewrite_by_lua 'ngx.location.capture(nil)';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body_like: 500 Internal Server Error
--- error_code: 500
=== TEST 14: capture location (default 0);
--- config
location /recur {
rewrite_by_lua '
local num = tonumber(ngx.var.arg_num) or 0;
ngx.print("num is: ", num, "\\n");
if (num > 0) then
res = ngx.location.capture("/recur?num="..tostring(num - 1));
ngx.print("status=", res.status, " ");
ngx.print("body=", res.body, "\\n");
else
ngx.print("end\\n");
end
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /recur
--- response_body
num is: 0
end
=== TEST 15: capture location
--- config
location /recur {
rewrite_by_lua '
local num = tonumber(ngx.var.arg_num) or 0;
ngx.print("num is: ", num, "\\n");
if (num > 0) then
res = ngx.location.capture("/recur?num="..tostring(num - 1));
ngx.print("status=", res.status, " ");
ngx.print("body=", res.body);
else
ngx.print("end\\n");
end
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /recur?num=3
--- response_body
num is: 3
status=200 body=num is: 2
status=200 body=num is: 1
status=200 body=num is: 0
end
=== TEST 16: setting nginx variables from within Lua
--- config
location /set {
set $a "";
rewrite_by_lua 'ngx.var.a = 32; ngx.say(ngx.var.a)';
content_by_lua 'ngx.exit(ngx.OK)';
add_header Foo $a;
}
--- request
GET /set
--- response_headers
Foo: 32
--- response_body
32
=== TEST 17: nginx quote sql string 1
--- config
location /set {
set $a 'hello\n\r\'"\\'; # this runs after rewrite_by_lua
rewrite_by_lua 'ngx.say(ngx.quote_sql_str(ngx.var.a))';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /set
--- response_body
'hello\n\r\'\"\\'
=== TEST 18: nginx quote sql string 2
--- config
location /set {
#set $a "hello\n\r'\"\\";
rewrite_by_lua 'ngx.say(ngx.quote_sql_str("hello\\n\\r\'\\"\\\\"))';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /set
--- response_body
'hello\n\r\'\"\\'
=== TEST 19: use dollar
--- config
location /set {
rewrite_by_lua '
local s = "hello 112";
ngx.say(string.find(s, "%d+$"))';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /set
--- response_body
79
=== TEST 20: subrequests do not share variables of main requests by default
--- config
location /sub {
echo $a;
}
location /parent {
set $a 12;
rewrite_by_lua 'res = ngx.location.capture("/sub"); ngx.print(res.body)';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /parent
--- response_body eval: "\n"
=== TEST 21: subrequests can share variables of main requests
--- config
location /sub {
echo $a;
}
location /parent {
set $a '';
rewrite_by_lua '
ngx.var.a = 12;
res = ngx.location.capture(
"/sub",
{ share_all_vars = true }
);
ngx.print(res.body)
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /parent
--- response_body
12
=== TEST 22: main requests use subrequests' variables
--- config
location /sub {
set $a 12;
}
location /parent {
rewrite_by_lua '
res = ngx.location.capture("/sub", { share_all_vars = true });
ngx.say(ngx.var.a)
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /parent
--- response_body
12
=== TEST 23: main requests do NOT use subrequests' variables
--- config
location /sub {
set $a 12;
content_by_lua return;
}
location /parent {
rewrite_by_lua '
res = ngx.location.capture("/sub", { share_all_vars = false });
ngx.say(ngx.var.a)
';
content_by_lua return;
}
--- request
GET /parent
--- response_body_like eval: "\n"
=== TEST 24: capture location headers
--- config
location /other {
default_type 'foo/bar';
echo "hello, world";
}
location /lua {
rewrite_by_lua '
res = ngx.location.capture("/other");
ngx.say("type: ", res.header["Content-Type"]);
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body
type: foo/bar
=== TEST 25: capture location headers
--- config
location /other {
default_type 'foo/bar';
rewrite_by_lua '
ngx.header.Bar = "Bah";
';
content_by_lua 'ngx.exit(ngx.OK)';
}
location /lua {
rewrite_by_lua '
res = ngx.location.capture("/other");
ngx.say("type: ", res.header["Content-Type"]);
ngx.say("Bar: ", res.header["Bar"]);
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body
type: foo/bar
Bar: Bah
=== TEST 26: capture location headers
--- config
location /other {
default_type 'foo/bar';
rewrite_by_lua '
ngx.header.Bar = "Bah";
ngx.header.Bar = nil;
';
content_by_lua 'ngx.exit(ngx.OK)';
}
location /lua {
rewrite_by_lua '
res = ngx.location.capture("/other");
ngx.say("type: ", res.header["Content-Type"]);
ngx.say("Bar: ", res.header["Bar"] or "nil");
';
content_by_lua 'ngx.exit(ngx.OK)';
}
--- request
GET /lua
--- response_body
type: foo/bar
Bar: nil
=== TEST 27: rewrite_by_lua runs before ngx_access
--- config
location /lua {
deny all;
rewrite_by_lua '
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
';
content_by_lua return;
}
--- request
GET /lua
--- response_body_like: 500 Internal Server Error
--- error_code: 500
=== TEST 28: rewrite_by_lua shouldn't send headers automatically (on simple return)
--- config
location /lua {
rewrite_by_lua 'return';
proxy_pass http://127.0.0.1:$server_port/foo;
}
location = /foo {
default_type 'text/css';
add_header Bar Baz;
echo foo;
}
--- request
GET /lua
--- response_headers
Bar: Baz
Content-Type: text/css
--- response_body
foo
=== TEST 29: rewrite_by_lua shouldn't send headers automatically (on simple exit)
--- config
location /lua {
rewrite_by_lua 'ngx.exit(ngx.OK)';
proxy_pass http://127.0.0.1:$server_port/foo;
}
location = /foo {
default_type 'text/css';
add_header Bar Baz;
echo foo;
}
--- request
GET /lua
--- response_headers
Bar: Baz
Content-Type: text/css
--- response_body
foo
=== TEST 30: short circuit
--- config
location /lua {
rewrite_by_lua '
ngx.say("Hi")
ngx.eof()
ngx.exit(ngx.HTTP_OK)
';
content_by_lua '
print("HERE")
ngx.print("BAD")
';
}
--- request
GET /lua
--- response_body
Hi
=== TEST 31: nginx vars in script path
--- config
location ~ /lua/(.+)$ {
rewrite_by_lua_file html/$1.lua;
content_by_lua '
print("HERE")
ngx.print("BAD")
';
}
--- user_files
>>> hi.lua
ngx.say("Hi")
ngx.eof()
ngx.exit(ngx.HTTP_OK)
--- request
GET /lua/hi
--- response_body
Hi
=== TEST 32: phase postponing works for various locations
--- config
location ~ '^/lua/(.+)' {
set $path $1;
rewrite_by_lua 'ngx.say(ngx.var.path)';
content_by_lua return;
}
location ~ '^/lua2/(.+)' {
set $path $1;
rewrite_by_lua 'ngx.say(ngx.var.path)';
content_by_lua return;
}
location /main {
echo_location /lua/foo;
echo_location /lua/bar;
echo_location /lua2/baz;
echo_location /lua2/bah;
}
--- request
GET /main
--- response_body
foo
bar
baz
bah
=== TEST 33: server rewrite_by_lua
--- config
rewrite_by_lua 'ngx.header["X-Foo"] = "bar" -- ngx.send_headers()';
--- request
GET /
--- response_body chop
<html><head><title>It works!</title></head><body>It works!</body></html>
--- response_headers
X-Foo: bar
--- no_error_log
[error]
=== TEST 34: server rewrite_by_lua_file
--- config
rewrite_by_lua_file html/foo.lua;
--- user_files
>>> foo.lua
ngx.header["X-Foo"] = "bar" -- ngx.send_headers()
--- request
GET /
--- response_body chop
<html><head><title>It works!</title></head><body>It works!</body></html>
--- response_headers
X-Foo: bar
=== TEST 35: rewrite last before rewrite_by_lua
--- config
location /main {
rewrite ^/main/xyz\.html$ /abc.html last;
rewrite_by_lua 'ngx.exit(503)';
}
location ~ /abc.html {
echo abc;
}
--- request
GET /main/xyz.html
--- response_body
abc
=== TEST 36: rewrite last before rewrite_by_lua_file
--- config
location /main {
rewrite ^/main/xyz\.html$ /abc.html last;
rewrite_by_lua_file html/exit.lua;
}
location ~ /abc.html {
echo abc;
}
--- user_files
>>> exit.lua
ngx.exit(503)
--- request
GET /main/xyz.html
--- response_body
abc
=== TEST 37: rewrite before rewrite_by_lua
--- config
location /main {
rewrite ^/main/xyz\.html$ /abc.html;
rewrite_by_lua 'ngx.exit(503)';
}
location ~ /abc.html {
echo abc;
}
--- request
GET /main/xyz.html
--- response_body
abc
=== TEST 38: rewrite break before rewrite_by_lua
--- config
location /main {
rewrite ^/main/xyz\.html$ /abc.html break;
rewrite_by_lua 'ngx.exit(503)';
}
location ~ /abc.html {
echo abc;
}
--- request
GET /main/xyz.html
--- response_body_like: 503 Service Temporarily Unavailable
--- error_code: 503
=== TEST 39: Lua file does not exist
--- config
location /lua {
rewrite_by_lua_file html/test2.lua;
}
--- user_files
>>> test.lua
v = ngx.var["request_uri"]
ngx.print("request_uri: ", v, "\n")
--- request
GET /lua?a=1&b=2
--- response_body_like: 500 Internal Server Error
--- error_code: 500
--- error_log eval
qr/failed to load external Lua file: cannot open .*? No such file or directory/