| # vim:set ft= ts=4 sw=4 et fdm=marker: |
| |
| use lib 'lib'; |
| use Test::Nginx::Socket::Lua; |
| |
| repeat_each(2); |
| |
| plan tests => repeat_each() * (3 * blocks() + 8); |
| |
| our $HtmlDir = html_dir; |
| |
| $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; |
| $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; |
| |
| log_level 'warn'; |
| |
| no_long_string(); |
| #no_diff(); |
| #no_shuffle(); |
| check_accum_error_log(); |
| run_tests(); |
| |
| __DATA__ |
| |
| === TEST 1: sanity |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| local port = ngx.var.port |
| udp:settimeout(1000) -- 1 sec |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected") |
| |
| local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body eval |
| "connected\nreceived 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" |
| --- no_error_log |
| [error] |
| --- log_level: debug |
| --- error_log |
| lua udp socket receive buffer size: 8192 |
| |
| |
| |
| === TEST 2: multiple parallel queries |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| local port = ngx.var.port |
| udp:settimeout(1000) -- 1 sec |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected") |
| |
| local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| req = "\\0\\2\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| ngx.sleep(0.05) |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("1: received ", #data, " bytes: ", data) |
| |
| data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("2: received ", #data, " bytes: ", data) |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body_like eval |
| "^connected\n" |
| ."1: received 12 bytes: " |
| ."\x{00}[\1\2]\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" |
| ."2: received 12 bytes: " |
| ."\x{00}[\1\2]\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}\$" |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 3: access a TCP interface |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_SERVER_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| local port = ngx.var.port |
| udp:settimeout(1000) -- 1 sec |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected") |
| |
| local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body |
| connected |
| failed to receive data: connection refused |
| --- error_log eval |
| qr/recv\(\) failed \(\d+: Connection refused\)/ |
| |
| |
| |
| === TEST 4: access conflicts of connect() on shared udp objects |
| --- http_config |
| lua_package_path '$prefix/html/?.lua;;'; |
| --- config |
| server_tokens off; |
| location /main { |
| content_by_lua ' |
| local reqs = {} |
| for i = 1, 170 do |
| table.insert(reqs, {"/t"}) |
| end |
| local resps = {ngx.location.capture_multi(reqs)} |
| for i = 1, 170 do |
| ngx.say(resps[i].status) |
| end |
| '; |
| } |
| |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local port = ngx.var.port |
| local foo = require "foo" |
| local udp = foo.get_udp() |
| |
| udp:settimeout(100) -- 100 ms |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.log(ngx.ERR, "failed to connect: ", err) |
| return ngx.exit(500) |
| end |
| |
| ngx.say("connected") |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- user_files |
| >>> foo.lua |
| module("foo", package.seeall) |
| |
| local udp |
| |
| function get_udp() |
| if not udp then |
| udp = ngx.socket.udp() |
| end |
| |
| return udp |
| end |
| |
| --- stap2 |
| M(http-lua-info) { |
| printf("udp resume: %p\n", $coctx) |
| print_ubacktrace() |
| } |
| |
| --- request |
| GET /main |
| --- response_body_like: \b500\b |
| --- error_log |
| failed to connect: socket busy |
| |
| |
| |
| === TEST 5: access conflicts of receive() on shared udp objects |
| --- http_config |
| lua_package_path '$prefix/html/?.lua;;'; |
| --- config |
| server_tokens off; |
| location /main { |
| content_by_lua ' |
| local reqs = {} |
| for i = 1, 170 do |
| table.insert(reqs, {"/t"}) |
| end |
| local resps = {ngx.location.capture_multi(reqs)} |
| for i = 1, 170 do |
| ngx.say(resps[i].status) |
| end |
| '; |
| } |
| |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local port = ngx.var.port |
| local foo = require "foo" |
| local udp = foo.get_udp(port) |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.log(ngx.ERR, "failed to receive data: ", err) |
| return ngx.exit(500) |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- user_files |
| >>> foo.lua |
| module("foo", package.seeall) |
| |
| local udp |
| |
| function get_udp(port) |
| if not udp then |
| udp = ngx.socket.udp() |
| |
| udp:settimeout(100) -- 100ms |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.log(ngx.ERR, "failed to connect: ", err) |
| return ngx.exit(500) |
| end |
| end |
| |
| return udp |
| end |
| --- request |
| GET /main |
| --- response_body_like: \b500\b |
| --- error_log |
| failed to receive data: socket busy |
| |
| |
| |
| === TEST 6: connect again immediately |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| |
| content_by_lua ' |
| local sock = ngx.socket.udp() |
| local port = ngx.var.port |
| |
| local ok, err = sock:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected: ", ok) |
| |
| ok, err = sock:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected again: ", ok) |
| |
| local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| local ok, err = sock:send(req) |
| if not ok then |
| ngx.say("failed to send request: ", err) |
| return |
| end |
| ngx.say("request sent: ", ok) |
| |
| local line, err = sock:receive() |
| if line then |
| ngx.say("received: ", line) |
| |
| else |
| ngx.say("failed to receive: ", err) |
| end |
| |
| ok, err = sock:close() |
| ngx.say("close: ", ok, " ", err) |
| '; |
| } |
| |
| location /foo { |
| echo foo; |
| more_clear_headers Date; |
| } |
| --- request |
| GET /t |
| --- response_body eval |
| "connected: 1 |
| connected again: 1 |
| request sent: 1 |
| received: \0\1\0\0\0\1\0\0OK\r\n |
| close: 1 nil |
| " |
| --- no_error_log |
| [error] |
| --- error_log eval |
| ["lua reuse socket upstream", "lua udp socket reconnect without shutting down"] |
| --- log_level: debug |
| |
| |
| |
| === TEST 7: recv timeout |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| |
| content_by_lua ' |
| local port = ngx.var.port |
| |
| local sock = ngx.socket.udp() |
| sock:settimeout(100) -- 100 ms |
| |
| local ok, err = sock:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected: ", ok) |
| |
| local line, err = sock:receive() |
| if line then |
| ngx.say("received: ", line) |
| |
| else |
| ngx.say("failed to receive: ", err) |
| end |
| |
| -- ok, err = sock:close() |
| -- ngx.say("close: ", ok, " ", err) |
| '; |
| } |
| |
| location /foo { |
| echo foo; |
| more_clear_headers Date; |
| } |
| --- request |
| GET /t |
| --- response_body |
| connected: 1 |
| failed to receive: timeout |
| --- error_log |
| lua udp socket read timed out |
| |
| |
| |
| === TEST 8: with an explicit receive buffer size argument |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| local port = ngx.var.port |
| udp:settimeout(1000) -- 1 sec |
| |
| local ok, err = udp:setpeername("127.0.0.1", port) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected") |
| |
| local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive(1400) |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body eval |
| "connected\nreceived 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" |
| --- no_error_log |
| [error] |
| --- log_level: debug |
| --- error_log |
| lua udp socket receive buffer size: 1400 |
| |
| |
| |
| === TEST 9: read timeout and re-receive |
| --- config |
| location = /t { |
| content_by_lua ' |
| local udp = ngx.socket.udp() |
| udp:settimeout(30) |
| local ok, err = udp:setpeername("127.0.0.1", 19232) |
| if not ok then |
| ngx.say("failed to setpeername: ", err) |
| return |
| end |
| local ok, err = udp:send("blah") |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| for i = 1, 2 do |
| local data, err = udp:receive() |
| if err == "timeout" then |
| -- continue |
| else |
| if not data then |
| ngx.say("failed to receive: ", err) |
| return |
| end |
| ngx.say("received: ", data) |
| return |
| end |
| end |
| |
| ngx.say("timed out") |
| '; |
| } |
| --- udp_listen: 19232 |
| --- udp_reply: hello world |
| --- udp_reply_delay: 45ms |
| --- request |
| GET /t |
| --- response_body |
| received: hello world |
| --- error_log |
| lua udp socket read timed out |
| |
| |
| |
| === TEST 10: access the google DNS server (using IP addr) |
| --- config |
| server_tokens off; |
| location /t { |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| udp:settimeout(2000) -- 2 sec |
| |
| local ok, err = udp:setpeername("8.8.8.8", 53) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| local req = "\\0}\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\6google\\3com\\0\\0\\1\\0\\1" |
| |
| -- ngx.print(req) |
| -- do return end |
| |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| |
| if string.match(data, "\\3www\\6google\\3com") then |
| ngx.say("received a good response.") |
| else |
| ngx.say("received a bad response: ", #data, " bytes: ", data) |
| end |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body |
| received a good response. |
| --- no_error_log |
| [error] |
| --- log_level: debug |
| --- error_log |
| lua udp socket receive buffer size: 8192 |
| |
| |
| |
| === TEST 11: access the google DNS server (using domain names) |
| --- config |
| server_tokens off; |
| resolver $TEST_NGINX_RESOLVER; |
| location /t { |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| udp:settimeout(2000) -- 2 sec |
| |
| local ok, err = udp:setpeername("google-public-dns-a.google.com", 53) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| local req = "\\0}\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\6google\\3com\\0\\0\\1\\0\\1" |
| |
| -- ngx.print(req) |
| -- do return end |
| |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| |
| if string.match(data, "\\3www\\6google\\3com") then |
| ngx.say("received a good response.") |
| else |
| ngx.say("received a bad response: ", #data, " bytes: ", data) |
| end |
| '; |
| } |
| --- request |
| GET /t |
| --- response_body |
| received a good response. |
| --- no_error_log |
| [error] |
| --- log_level: debug |
| --- error_log |
| lua udp socket receive buffer size: 8192 |
| |
| |
| |
| === TEST 12: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) |
| --- config |
| resolver 8.8.8.8; |
| |
| location = /sub { |
| content_by_lua ' |
| local sock = ngx.socket.udp() |
| local ok, err = sock:setpeername("xxx", 80) |
| if not ok then |
| ngx.say("failed to connect to xxx: ", err) |
| return |
| end |
| ngx.say("successfully connected to xxx!") |
| sock:close() |
| '; |
| } |
| |
| location = /lua { |
| content_by_lua ' |
| local res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /sub |
| |
| --- stap |
| F(ngx_resolve_name_done) { |
| println("resolve name done") |
| } |
| |
| --- stap_out |
| resolve name done |
| |
| --- response_body_like chop |
| ^failed to connect to xxx: xxx could not be resolved.*?Host not found |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 13: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) |
| --- config |
| resolver 8.8.8.8; |
| resolver_timeout 3s; |
| |
| location = /sub { |
| content_by_lua ' |
| if not package.i then |
| package.i = 1 |
| end |
| |
| local servers = {"openresty.org", "agentzh.org", "sregex.org"} |
| local server = servers[package.i] |
| package.i = package.i + 1 |
| |
| local sock = ngx.socket.udp() |
| local ok, err = sock:setpeername(server, 80) |
| if not ok then |
| ngx.say("failed to connect to agentzh.org: ", err) |
| return |
| end |
| ngx.say("successfully connected to xxx!") |
| sock:close() |
| '; |
| } |
| |
| location = /lua { |
| content_by_lua ' |
| local res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| '; |
| } |
| --- request |
| GET /lua |
| --- response_body |
| successfully connected to xxx! |
| |
| --- no_error_log |
| [error] |
| --- timeout: 5 |
| |
| |
| |
| === TEST 14: datagram unix domain socket |
| --- config |
| server_tokens off; |
| location /t { |
| #set $port 5000; |
| set $port $TEST_NGINX_MEMCACHED_PORT; |
| #set $port 1234; |
| |
| content_by_lua ' |
| local socket = ngx.socket |
| -- local socket = require "socket" |
| |
| local udp = socket.udp() |
| |
| local port = ngx.var.port |
| udp:settimeout(1000) -- 1 sec |
| |
| local ok, err = udp:setpeername("unix:a.sock") |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| |
| ngx.say("connected") |
| |
| local req = "hello,\\nserver" |
| local ok, err = udp:send(req) |
| if not ok then |
| ngx.say("failed to send: ", err) |
| return |
| end |
| |
| local data, err = udp:receive() |
| if not data then |
| ngx.say("failed to receive data: ", err) |
| return |
| end |
| ngx.print("received ", #data, " bytes: ", data) |
| '; |
| } |
| --- request |
| GET /t |
| |
| --- udp_listen: a.sock |
| --- udp_reply |
| hello, |
| client |
| |
| --- response_body |
| connected |
| received 14 bytes: hello, |
| client |
| |
| --- stap2 |
| probe syscall.socket, syscall.connect { |
| print(name, "(", argstr, ")") |
| } |
| |
| probe syscall.socket.return, syscall.connect.return { |
| println(" = ", retstr) |
| } |
| --- no_error_log |
| [error] |
| [crit] |
| --- skip_eval: 3: $^O ne 'linux' |
| |