| # vim:set ft= ts=4 sw=4 et fdm=marker: |
| use lib 'lib'; |
| use Test::Nginx::Socket::Lua; |
| |
| #master_on(); |
| #workers(1); |
| #worker_connections(1014); |
| #log_level('warn'); |
| #master_process_enabled(1); |
| |
| repeat_each(2); |
| |
| plan tests => repeat_each() * (blocks() * 3 + 21); |
| |
| $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; |
| |
| #no_diff(); |
| no_long_string(); |
| #no_shuffle(); |
| |
| run_tests(); |
| |
| __DATA__ |
| |
| === TEST 1: DELETE |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_DELETE }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| DELETE |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 2: DELETE (proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_DELETE }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| DELETE |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 3: POST (nobody, proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /t { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_POST }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body |
| POST |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 4: HEAD |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_HEAD }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| HEAD |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 5: explicit GET |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_GET }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| GET |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 6: implicit GET |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo") |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| GET |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 7: implicit GET (empty option table) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", {}) |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| GET |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 8: PUT (nobody, proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo_read_request_body; |
| |
| echo $echo_request_method; |
| echo_request_body; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_PUT, body = "hello" }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body chomp |
| PUT |
| hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 9: PUT (nobody, no proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| #echo_read_request_body; |
| |
| echo $echo_request_method; |
| #echo $echo_request_body; |
| echo_request_body; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_PUT, body = "hello" }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body chomp |
| PUT |
| hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 10: PUT (nobody, no proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| #echo_read_request_body; |
| |
| echo $echo_request_method; |
| #echo $echo_request_body; |
| echo_request_body; |
| #echo "[$http_content_length]"; |
| echo; |
| } |
| |
| location /foo { |
| echo $echo_request_method; |
| echo -n "[$http_content_length]"; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_PUT, body = "hello" }); |
| |
| ngx.print(res.body) |
| |
| res = ngx.location.capture("/foo") |
| ngx.say(res.body) |
| |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| PUT |
| hello |
| GET |
| [] |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 11: POST (with body, proxy method) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo_read_request_body; |
| |
| echo $echo_request_method; |
| echo_request_body; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_POST, body = "hello" }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body chomp |
| POST |
| hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 12: POST (with body, memc method) |
| --- config |
| location /flush { |
| set $memc_cmd flush_all; |
| memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /memc { |
| set $memc_key $echo_request_uri; |
| set $memc_exptime 600; |
| memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.location.capture("/flush"); |
| |
| res = ngx.location.capture("/memc"); |
| ngx.say("GET: " .. res.status); |
| |
| res = ngx.location.capture("/memc", |
| { method = ngx.HTTP_PUT, body = "hello" }); |
| ngx.say("PUT: " .. res.status); |
| |
| res = ngx.location.capture("/memc"); |
| ngx.say("cached: " .. res.body); |
| |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| GET: 404 |
| PUT: 201 |
| cached: hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 13: POST (with body, memc method) |
| --- config |
| location /flush { |
| set $memc_cmd flush_all; |
| memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /memc { |
| set $memc_cmd ""; |
| set $memc_key $echo_request_uri; |
| set $memc_exptime 600; |
| memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.location.capture("/flush", |
| { share_all_vars = true }); |
| |
| res = ngx.location.capture("/memc", |
| { share_all_vars = true }); |
| ngx.say("GET: " .. res.status); |
| |
| res = ngx.location.capture("/memc", |
| { method = ngx.HTTP_PUT, body = "hello", share_all_vars = true }); |
| ngx.say("PUT: " .. res.status); |
| |
| res = ngx.location.capture("/memc", { share_all_vars = true }); |
| ngx.say("cached: " .. res.body); |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| GET: 404 |
| PUT: 201 |
| cached: hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 14: emtpy args option table |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = {} }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body eval: "\n" |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 15: non-empty args option table (1 pair) |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = { ["fo="] = "=>" } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| fo%3d=%3d%3e |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 16: non-empty args option table (2 pairs) |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = { ["fo="] = "=>", |
| ["="] = ":" } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body_like chop |
| ^(?:fo%3d=%3d%3e\&%3d=%3a|%3d=%3a\&fo%3d=%3d%3e)$ |
| --- no_error_log |
| [error] |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 17: non-empty args option table (2 pairs, no special chars) |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = { foo = 3, |
| bar = "hello" } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body_like chop |
| ^(?:bar=hello\&foo=3|foo=3\&bar=hello)$ |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 18: non-empty args option table (number key) |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = { [57] = "hi" } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body_like: 500 Internal Server Error |
| --- error_code: 500 |
| --- error_log |
| attempt to use a non-string key in the "args" option table |
| |
| |
| |
| === TEST 19: non-empty args option table (plain arrays) |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { args = { "hi" } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body_like: 500 Internal Server Error |
| --- error_code: 500 |
| --- error_log |
| attempt to use a non-string key in the "args" option table |
| |
| |
| |
| === TEST 20: more args |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo?a=3", |
| { args = { b = 4 } }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| a=3&b=4 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 21: more args |
| --- config |
| location /foo { |
| echo $query_string; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo?a=3", |
| { args = "b=4" }) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| a=3&b=4 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 22: is_subrequest in main request |
| --- config |
| location /lua { |
| content_by_lua ' |
| if ngx.is_subrequest then |
| ngx.say("sub req") |
| else |
| ngx.say("main req") |
| end |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| main req |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 23: is_subrequest in sub request |
| --- config |
| location /main { |
| echo_location /lua; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| if ngx.is_subrequest then |
| ngx.say("sub req") |
| else |
| ngx.say("main req") |
| end |
| '; |
| } |
| --- request |
| GET /main |
| --- response_body |
| sub req |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 24: is_subrequest in sub request in set_by_lua |
| --- config |
| location /main { |
| echo_location /lua; |
| } |
| |
| location /lua { |
| set_by_lua $a ' |
| if ngx.is_subrequest then |
| return "sub req" |
| else |
| return "main req" |
| end |
| '; |
| echo $a; |
| } |
| --- request |
| GET /main |
| --- response_body |
| sub req |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 25: header inheritance bug (without body) (github issue 38) |
| https://github.com/chaoslawful/lua-nginx-module/issues/38 |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo -n $http_foo; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_GET }); |
| ngx.say("header foo: [", res.body, "]") |
| '; |
| } |
| --- request |
| GET /lua |
| --- more_headers |
| Foo: bar |
| --- response_body |
| header foo: [bar] |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 26: header inheritance bug (with body) (github issue 38) |
| https://github.com/chaoslawful/lua-nginx-module/issues/38 |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo -n $http_foo; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { body = "abc" }); |
| ngx.say("header foo: [", res.body, "]") |
| '; |
| } |
| --- request |
| GET /lua |
| --- more_headers |
| Foo: bar |
| --- response_body |
| header foo: [bar] |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 27: lua calls lua via subrequests |
| --- config |
| location /a { |
| content_by_lua ' |
| ngx.say("hello, a"); |
| '; |
| } |
| location /b { |
| content_by_lua ' |
| ngx.say("hello, b"); |
| '; |
| } |
| location /c { |
| content_by_lua ' |
| ngx.say("hello, c"); |
| '; |
| } |
| location /main { |
| content_by_lua ' |
| res1, res2 = ngx.location.capture_multi({{"/a"}, {"/b"}}) |
| res3 = ngx.location.capture("/c") |
| ngx.print(res1.body, res2.body, res3.body) |
| '; |
| } |
| --- request |
| GET /main |
| --- response_body |
| hello, a |
| hello, b |
| hello, c |
| --- error_log |
| lua reuse free buf memory |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 28: POST (with body, proxy method, main request is a POST too) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo_read_request_body; |
| |
| echo $echo_request_method; |
| echo_request_body; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_POST, body = "hello" }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| POST /lua |
| hi |
| --- response_body chomp |
| POST |
| hello |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 29: Last-Modified response header for static file subrequest |
| --- config |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo.html") |
| |
| ngx.say(res.status) |
| ngx.say(res.header["Last-Modified"]) |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- user_files |
| >>> foo.html |
| hello, static file |
| --- response_body_like chomp |
| ^200 |
| [A-Za-z]+, \d{1,2} [A-Za-z]+ \d{4} \d{2}:\d{2}:\d{2} GMT |
| hello, static file$ |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 30: custom ctx table for subrequest |
| --- config |
| location /sub { |
| content_by_lua ' |
| ngx.ctx.foo = "bar"; |
| '; |
| } |
| location /lua { |
| content_by_lua ' |
| local ctx = {} |
| res = ngx.location.capture("/sub", { ctx = ctx }) |
| |
| ngx.say(ctx.foo); |
| ngx.say(ngx.ctx.foo); |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| bar |
| nil |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 31: share the ctx with the parent |
| --- config |
| location /sub { |
| content_by_lua ' |
| ngx.ctx.foo = "bar"; |
| '; |
| } |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/sub", { ctx = ngx.ctx }) |
| ngx.say(ngx.ctx.foo); |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| bar |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 32: test memcached with subrequests |
| --- http_config |
| upstream memc { |
| server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; |
| keepalive 100; |
| } |
| --- config |
| location /memc { |
| set $memc_key some_key; |
| set $memc_exptime 600; |
| memc_pass memc; |
| } |
| |
| location /t { |
| content_by_lua ' |
| res = ngx.location.capture("/memc", |
| { method = ngx.HTTP_PUT, body = "hello 1234" }); |
| -- ngx.say("PUT: " .. res.status); |
| |
| res = ngx.location.capture("/memc"); |
| ngx.say("some_key: " .. res.body); |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body |
| some_key: hello 1234 |
| --- error_log |
| lua reuse free buf chain, but reallocate memory because |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 33: main POST, sub GET (main does not read the body) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.var.request_method) |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| #proxy_pass http://127.0.0.1:8892/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_GET }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| POST /lua |
| hello, world |
| --- response_body |
| GET |
| nil |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 34: main POST, sub GET (main has read the body) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.var.request_method) |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| #proxy_pass http://127.0.0.1:8892/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_GET }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| POST /lua |
| hello, world |
| --- response_body |
| GET |
| nil |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 35: main POST, sub POST (inherit bodies directly) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.var.request_method) |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| #proxy_pass http://127.0.0.1:8892/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_POST }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| POST /lua |
| hello, world |
| --- response_body |
| POST |
| hello, world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 36: main POST, sub PUT (inherit bodies directly) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.var.request_method) |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /foo { |
| proxy_pass http://127.0.0.1:$server_port/other; |
| #proxy_pass http://127.0.0.1:8892/other; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| res = ngx.location.capture("/foo", |
| { method = ngx.HTTP_PUT }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| POST /lua |
| hello, world |
| --- response_body |
| PUT |
| hello, world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 37: recursive calls |
| --- config |
| location /t { |
| content_by_lua ' |
| ngx.location.capture("/t") |
| '; |
| } |
| --- request |
| GET /t |
| --- ignore_response |
| --- error_log |
| subrequests cycle while processing "/t" |
| |
| |
| |
| === TEST 38: OPTIONS |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_OPTIONS }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| OPTIONS |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 39: OPTIONS with a body |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| echo $echo_request_method; |
| echo_request_body; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_OPTIONS, body = "hello world" }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body chop |
| OPTIONS |
| hello world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 40: encode args table with a multi-value arg. |
| --- config |
| location /t { |
| content_by_lua ' |
| local args = ngx.req.get_uri_args() |
| local res = ngx.location.capture("/sub", { args = args }) |
| ngx.print(res.body) |
| '; |
| } |
| |
| location /sub { |
| echo $query_string; |
| } |
| --- request |
| GET /t?r[]=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fjquery%2F1.7.2%2Fjquery.min.js&r[]=http%3A%2F%2Fajax.googleapis.com%3A80%2Fajax%2Flibs%2Fdojo%2F1.7.2%2Fdojo%2Fdojo.js.uncompressed.js |
| --- response_body |
| r%5b%5d=http%3a%2f%2fajax.googleapis.com%3a80%2fajax%2flibs%2fjquery%2f1.7.2%2fjquery.min.js&r%5b%5d=http%3a%2f%2fajax.googleapis.com%3a80%2fajax%2flibs%2fdojo%2f1.7.2%2fdojo%2fdojo.js.uncompressed.js |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 41: subrequests finalized with NGX_ERROR |
| --- config |
| location /sub { |
| content_by_lua ' |
| ngx.exit(ngx.ERROR) |
| '; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| '; |
| } |
| --- request |
| GET /main |
| --- response_body |
| status: 500 |
| body: |
| |
| |
| |
| === TEST 42: subrequests finalized with 500 |
| --- config |
| location /sub { |
| return 500; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| '; |
| } |
| --- request |
| GET /main |
| --- response_body |
| status: 500 |
| body: |
| |
| |
| |
| === TEST 43: subrequests with an output body filter returning NGX_ERROR |
| --- config |
| location /sub { |
| echo hello world; |
| body_filter_by_lua ' |
| return ngx.ERROR |
| '; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| '; |
| } |
| --- request |
| GET /main |
| --- stap2 |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| --- response_body |
| --- error_code |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 44: subrequests truncated in its response body due to premature connection close (nonbuffered) |
| --- config |
| server_tokens off; |
| location /memc { |
| internal; |
| |
| set $memc_key 'foo'; |
| #set $memc_exptime 300; |
| memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/memc") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19112 |
| --- tcp_query_len: 9 |
| --- tcp_reply eval |
| "VALUE foo 0 1024\r\nhello world" |
| |
| --- stap2 |
| F(ngx_http_lua_capture_body_filter) { |
| if (pid() == target() && $r != $r->main) { |
| printf("lua capture body output: %s\n", ngx_chain_dump($in)) |
| if ($in->buf->last_in_chain) { |
| print_ubacktrace() |
| } |
| } |
| } |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| --- error_log |
| upstream prematurely closed connection |
| |
| |
| |
| === TEST 45: subrequests truncated in its response body due to upstream read timeout (nonbuffered) |
| --- config |
| memc_read_timeout 100ms; |
| location /memc { |
| internal; |
| |
| set $memc_key 'foo'; |
| #set $memc_exptime 300; |
| memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/memc") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19112 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "VALUE foo 0 1024\r\nhello world" |
| |
| --- stap2 |
| F(ngx_http_lua_capture_body_filter) { |
| if (pid() == target() && $r != $r->main) { |
| printf("lua capture body output: %s\n", ngx_chain_dump($in)) |
| //if ($in->buf->last_in_chain) { |
| print_ubacktrace() |
| //} |
| } |
| } |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| conn err: 110: upstream timed out |
| upstream fin req: error=0 eof=0 rc=504 |
| post subreq: rc=0, status=200 |
| |
| --- response_body_like chop |
| ^status: 200 |
| body: [^\n]* |
| truncated: true |
| |
| --- error_log |
| upstream timed out |
| |
| |
| |
| === TEST 46: subrequests truncated in its response body due to premature connection close (buffered) |
| --- config |
| server_tokens off; |
| |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| |
| --- error_log |
| upstream prematurely closed connection |
| |
| |
| |
| === TEST 47: subrequests truncated in its response body due to read timeout (buffered) |
| --- config |
| location /proxy { |
| internal; |
| |
| proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| conn err: 110: upstream timed out |
| upstream fin req: error=0 eof=0 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: |
| truncated: true |
| |
| --- error_log |
| upstream timed out |
| |
| |
| |
| === TEST 48: subrequests truncated in its response body due to premature connection close (buffered, no content-length) |
| --- config |
| server_tokens off; |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=0 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: false |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 49: subrequests truncated in its response body due to read timeout (buffered, no content-length) |
| --- config |
| location /proxy { |
| internal; |
| |
| proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| conn err: 110: upstream timed out |
| upstream fin req: error=0 eof=0 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: |
| truncated: true |
| |
| --- error_log |
| upstream timed out |
| |
| |
| |
| === TEST 50: subrequests truncated in its response body due to premature connection close (nonbuffered, no content-length) |
| --- config |
| server_tokens off; |
| |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering off; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=0 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: false |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 51: subrequests truncated in its response body due to read timeout (nonbuffered, no content-length) |
| --- config |
| location /proxy { |
| internal; |
| |
| proxy_read_timeout 500ms; |
| proxy_buffering off; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| conn err: 110: upstream timed out |
| upstream fin req: error=0 eof=0 rc=504 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| |
| --- error_log |
| upstream timed out |
| |
| |
| |
| === TEST 52: forwarding in-memory request bodies to multiple subrequests |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| proxy_pass http://127.0.0.1:$server_port/back; |
| } |
| |
| location /back { |
| echo_read_request_body; |
| echo_request_body; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| for i = 1, 2 do |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_POST }); |
| |
| ngx.say(res.body) |
| end |
| '; |
| } |
| |
| --- request eval |
| "POST /lua |
| " . "hello world" |
| |
| --- response_body |
| hello world |
| hello world |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 53: forwarding in-file request bodies to multiple subrequests (client_body_in_file_only) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| proxy_pass http://127.0.0.1:$server_port/back; |
| } |
| |
| location /back { |
| echo_read_request_body; |
| echo_request_body; |
| } |
| |
| client_body_in_file_only on; |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| for i = 1, 2 do |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_POST }); |
| |
| ngx.say(res.body) |
| end |
| '; |
| } |
| |
| --- request eval |
| "POST /lua |
| " . "hello world" |
| |
| --- response_body |
| hello world |
| hello world |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 54: forwarding in-file request bodies to multiple subrequests (exceeding client_body_buffer_size) |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| proxy_pass http://127.0.0.1:$server_port/back; |
| } |
| |
| location /back { |
| echo_read_request_body; |
| echo_request_body; |
| } |
| |
| location /lua { |
| #client_body_in_file_only on; |
| client_body_buffer_size 1; |
| content_by_lua ' |
| ngx.req.read_body() |
| |
| for i = 1, 2 do |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_POST }); |
| |
| ngx.say(res.body) |
| end |
| '; |
| } |
| --- request eval |
| "POST /lua |
| " . ("hello world" x 100) |
| |
| --- stap2 |
| global valid = 0 |
| global fds |
| |
| F(ngx_http_handler) { valid = 1 } |
| |
| probe syscall.open { |
| if (valid && pid() == target()) { |
| print(name, "(", argstr, ")") |
| } |
| } |
| |
| probe syscall.close { |
| if (valid && pid() == target() && fds[sprintf("%d", $fd)]) { |
| println(name, "(", argstr, ")") |
| } |
| } |
| |
| probe syscall.unlink { |
| if (valid && pid() == target()) { |
| println(name, "(", argstr, ")") |
| } |
| } |
| |
| probe syscall.open.return { |
| if (valid && pid() == target()) { |
| println(" = ", retstr) |
| fds[retstr] = 1 |
| } |
| } |
| |
| F(ngx_http_lua_subrequest) { |
| println("lua subrequest") |
| } |
| |
| F(ngx_output_chain) { |
| printf("output chain: %s\n", ngx_chain_dump($in)) |
| } |
| |
| F(ngx_pool_run_cleanup_file) { |
| println("clean up file: ", $fd) |
| } |
| |
| --- response_body eval |
| ("hello world" x 100) . "\n" |
| . ("hello world" x 100) . "\n" |
| |
| --- no_error_log |
| [error] |
| --- error_log |
| a client request body is buffered to a temporary file |
| |
| |
| |
| === TEST 55: subrequests truncated in its response body due to premature connection close (buffered + chunked) |
| --- config |
| server_tokens off; |
| |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_http_version 1.1; |
| proxy_buffering on; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| |
| --- error_log |
| upstream prematurely closed connection |
| |
| |
| |
| === TEST 56: subrequests truncated in its response body due to premature connection close (nonbuffered + chunked) |
| --- config |
| server_tokens off; |
| |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_http_version 1.1; |
| proxy_buffering off; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| |
| --- error_log |
| upstream prematurely closed connection |
| |
| |
| |
| === TEST 57: subrequests truncated in its response body due to read timeout (buffered + chunked) |
| --- config |
| location /proxy { |
| internal; |
| |
| proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_http_version 1.1; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| conn err: 110: upstream timed out |
| upstream fin req: error=0 eof=0 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: |
| truncated: true |
| |
| --- error_log |
| upstream timed out |
| |
| |
| |
| === TEST 58: good chunked response (buffered) |
| --- config |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering on; |
| proxy_http_version 1.1; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=0 rc=0 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello |
| truncated: false |
| |
| |
| |
| === TEST 59: good chunked response (nonbuffered) |
| --- config |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering off; |
| proxy_http_version 1.1; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_no_close |
| --- tcp_reply eval |
| "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=0 rc=0 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello |
| truncated: false |
| |
| |
| |
| === TEST 60: subrequests truncated in its response body due to premature connection close (nonbuffered + proxy) |
| --- config |
| server_tokens off; |
| |
| location /proxy { |
| internal; |
| |
| #proxy_read_timeout 100ms; |
| proxy_buffering off; |
| proxy_pass http://127.0.0.1:19113; |
| } |
| |
| location /main { |
| content_by_lua ' |
| res = ngx.location.capture("/proxy") |
| ngx.say("status: ", res.status) |
| ngx.say("body: ", res.body) |
| ngx.say("truncated: ", res.truncated) |
| '; |
| } |
| --- request |
| GET /main |
| --- tcp_listen: 19113 |
| --- tcp_query_len: 65 |
| --- tcp_reply eval |
| "HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" |
| |
| --- stap |
| F(ngx_http_upstream_finalize_request) { |
| printf("upstream fin req: error=%d eof=%d rc=%d\n", |
| $r->upstream->peer->connection->read->error, |
| $r->upstream->peer->connection->read->eof, |
| $rc) |
| #print_ubacktrace() |
| } |
| F(ngx_connection_error) { |
| printf("conn err: %d: %s\n", $err, user_string($text)) |
| #print_ubacktrace() |
| } |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) |
| #print_ubacktrace() |
| } |
| /* |
| F(ngx_http_finalize_request) { |
| printf("finalize: %d\n", $rc) |
| } |
| */ |
| --- stap_out |
| upstream fin req: error=0 eof=1 rc=502 |
| post subreq: rc=0, status=200 |
| |
| --- response_body |
| status: 200 |
| body: hello world |
| truncated: true |
| |
| --- error_log |
| upstream prematurely closed connection |
| |
| |
| |
| === TEST 61: WebDAV methods |
| --- config |
| location /other { |
| echo "method: $echo_request_method"; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| local methods = { |
| ngx.HTTP_MKCOL, |
| ngx.HTTP_COPY, |
| ngx.HTTP_MOVE, |
| ngx.HTTP_PROPFIND, |
| ngx.HTTP_PROPPATCH, |
| ngx.HTTP_LOCK, |
| ngx.HTTP_UNLOCK, |
| ngx.HTTP_PATCH, |
| ngx.HTTP_TRACE, |
| } |
| |
| for i, method in ipairs(methods) do |
| res = ngx.location.capture("/other", |
| { method = method }) |
| ngx.print(res.body) |
| end |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| method: MKCOL |
| method: COPY |
| method: MOVE |
| method: PROPFIND |
| method: PROPPATCH |
| method: LOCK |
| method: UNLOCK |
| method: PATCH |
| method: TRACE |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 62: by default DELETE subrequests don't forward request bodies |
| --- config |
| location /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_DELETE }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| DELETE /lua |
| hello world |
| --- response_body |
| nil |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 63: DELETE subrequests do forward request bodies when always_forward_body == true |
| --- config |
| location = /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_DELETE, always_forward_body = true }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| DELETE /lua |
| hello world |
| --- response_body |
| hello world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 64: DELETE subrequests do forward request bodies when always_forward_body == true (on disk) |
| --- config |
| location = /other { |
| default_type 'foo/bar'; |
| content_by_lua ' |
| ngx.req.read_body() |
| ngx.say(ngx.req.get_body_data()) |
| '; |
| } |
| |
| location /lua { |
| content_by_lua ' |
| ngx.req.read_body() |
| res = ngx.location.capture("/other", |
| { method = ngx.HTTP_DELETE, always_forward_body = true }); |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| DELETE /lua |
| hello world |
| --- stap2 |
| global c |
| probe process("$LIBLUA_PATH").function("rehashtab") { |
| c++ |
| //print_ubacktrace() |
| printf("rehash: %d\n", c) |
| } |
| --- stap_out2 |
| --- response_body |
| hello world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 65: DELETE |
| --- config |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| '; |
| } |
| location = /sub { |
| echo hello; |
| echo world; |
| } |
| --- request |
| GET /t |
| --- response_body |
| hello |
| world |
| --- stap |
| F(ngx_http_lua_capture_header_filter) { |
| println("capture header filter") |
| } |
| |
| F(ngx_http_lua_capture_body_filter) { |
| println("capture body filter") |
| } |
| |
| --- stap_out |
| capture header filter |
| capture body filter |
| capture body filter |
| capture body filter |
| capture header filter |
| capture body filter |
| capture body filter |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 66: leafo test case 1 for assertion failures |
| --- config |
| location = /t { |
| echo hello; |
| } |
| |
| location /proxy { |
| internal; |
| rewrite_by_lua " |
| local req = ngx.req |
| print(ngx.var._url) |
| |
| for k,v in pairs(req.get_headers()) do |
| if k ~= 'content-length' then |
| req.clear_header(k) |
| end |
| end |
| |
| if ngx.ctx.headers then |
| for k,v in pairs(ngx.ctx.headers) do |
| req.set_header(k, v) |
| end |
| end |
| "; |
| |
| resolver 8.8.8.8; |
| proxy_http_version 1.1; |
| proxy_pass $_url; |
| } |
| |
| location /first { |
| set $_url ""; |
| content_by_lua ' |
| local res = ngx.location.capture("/proxy", { |
| ctx = { |
| headers = { |
| ["Content-type"] = "application/x-www-form-urlencoded" |
| } |
| }, |
| vars = { _url = "http://127.0.0.1:" .. ngx.var.server_port .. "/t" } |
| }) |
| |
| ngx.print(res.body) |
| |
| local res = ngx.location.capture("/proxy", { |
| ctx = { |
| headers = { |
| ["x-some-date"] = "Sun, 01 Dec 2013 11:47:41 GMT", |
| ["x-hello-world-header"] = "123412341234", |
| ["Authorization"] = "Hello" |
| } |
| }, |
| vars = { _url = "http://127.0.0.1:" .. ngx.var.server_port .. "/t" } |
| }) |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /first |
| --- response_body |
| hello |
| hello |
| --- no_error_log eval |
| [ |
| "[error]", |
| qr/Assertion .*? failed/ |
| ] |
| |
| |
| |
| === TEST 67: leafo test case 2 for assertion failures |
| --- config |
| location = /t { |
| echo hello; |
| } |
| |
| location /proxy { |
| internal; |
| rewrite_by_lua " |
| local req = ngx.req |
| print(ngx.var._url) |
| |
| for k,v in pairs(req.get_headers()) do |
| if k ~= 'content-length' then |
| req.clear_header(k) |
| end |
| end |
| |
| if ngx.ctx.headers then |
| for k,v in pairs(ngx.ctx.headers) do |
| req.set_header(k, v) |
| end |
| end |
| "; |
| |
| resolver 8.8.8.8; |
| proxy_http_version 1.1; |
| proxy_pass $_url; |
| } |
| |
| location /second { |
| set $_url ""; |
| content_by_lua ' |
| local res = ngx.location.capture("/proxy", { |
| method = ngx.HTTP_POST, |
| body = ("x"):rep(600), |
| ctx = { |
| headers = { |
| ["Content-type"] = "application/x-www-form-urlencoded" |
| } |
| }, |
| vars = { _url = "http://127.0.0.1:" .. ngx.var.server_port .. "/t" } |
| }) |
| |
| ngx.print(res.body) |
| |
| local res = ngx.location.capture("/proxy", { |
| ctx = { |
| headers = { |
| ["x-some-date"] = "Sun, 01 Dec 2013 11:47:41 GMT", |
| ["x-hello-world-header"] = "123412341234", |
| ["Authorization"] = "Hello" |
| } |
| }, |
| vars = { _url = "http://127.0.0.1:" .. ngx.var.server_port .. "/t" } |
| }) |
| |
| ngx.print(res.body) |
| |
| local res = ngx.location.capture("/proxy", { |
| vars = { _url = "http://127.0.0.1:" .. ngx.var.server_port .. "/t" } |
| }) |
| |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /second |
| --- response_body |
| hello |
| hello |
| hello |
| --- no_error_log eval |
| [ |
| "[error]", |
| qr/Assertion .*? failed/ |
| ] |
| |
| |
| |
| === TEST 68: fetch subrequest's builtin request headers |
| --- config |
| location = /sub { |
| echo "sr: User-Agent: $http_user_agent"; |
| echo "sr: Host: $http_host"; |
| } |
| |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) |
| ngx.say("pr: Host: ", ngx.var.http_host) |
| '; |
| } |
| --- request |
| GET /t |
| --- more_headers |
| User-Agent: foo |
| --- response_body |
| sr: User-Agent: foo |
| sr: Host: localhost |
| pr: User-Agent: foo |
| pr: Host: localhost |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 69: modify subrequest's builtin request headers |
| --- config |
| location = /sub { |
| rewrite_by_lua ' |
| ngx.req.set_header("User-Agent", "bar") |
| '; |
| echo "sr: User-Agent: $http_user_agent"; |
| echo "sr: Host: $http_host"; |
| } |
| |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) |
| ngx.say("pr: Host: ", ngx.var.http_host) |
| '; |
| } |
| --- request |
| GET /t |
| --- more_headers |
| User-Agent: foo |
| --- response_body |
| sr: User-Agent: bar |
| sr: Host: localhost |
| pr: User-Agent: foo |
| pr: Host: localhost |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 70: modify subrequest's builtin request headers (main req is POST) |
| --- config |
| location = /sub { |
| rewrite_by_lua ' |
| ngx.req.set_header("User-Agent", "bar") |
| '; |
| echo "sr: User-Agent: $http_user_agent"; |
| echo "sr: Host: $http_host"; |
| } |
| |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.say("pr: User-Agent: ", ngx.var.http_user_agent) |
| ngx.say("pr: Host: ", ngx.var.http_host) |
| '; |
| } |
| --- request |
| POST /t |
| hello world |
| --- more_headers |
| User-Agent: foo |
| --- response_body |
| sr: User-Agent: bar |
| sr: Host: localhost |
| pr: User-Agent: foo |
| pr: Host: localhost |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 71: duplicate request headers (main req is POST) |
| --- config |
| location = /sub { |
| echo "sr: Cookie: $http_cookie"; |
| } |
| |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.say("pr: Cookie: ", ngx.var.http_cookie) |
| '; |
| } |
| --- request |
| POST /t |
| hello world |
| --- more_headers |
| Cookie: foo |
| Cookie: bar |
| --- response_body |
| sr: Cookie: foo; bar |
| pr: Cookie: foo; bar |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 72: duplicate request headers (main req is GET) |
| --- config |
| location = /sub { |
| echo "sr: Cookie: $http_cookie"; |
| } |
| |
| location = /t { |
| content_by_lua ' |
| res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.say("pr: Cookie: ", ngx.var.http_cookie) |
| '; |
| } |
| --- request |
| GET /t |
| --- more_headers |
| Cookie: foo |
| Cookie: bar |
| --- response_body |
| sr: Cookie: foo; bar |
| pr: Cookie: foo; bar |
| |
| --- no_error_log |
| [error] |
| |