From 6d4150994bc1e43b2c00cef5f45696f2e043baaa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 12:24:19 -0800 Subject: [PATCH 0001/1981] added more info about r->main->count to the debugging logs. --- src/ngx_http_lua_accessby.c | 5 ++- src/ngx_http_lua_contentby.c | 5 ++- src/ngx_http_lua_logby.c | 5 ++- t/079-unused-directives.t | 78 ++++++++++++++++++------------------ 4 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 5f57af1149..a70c421932 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -32,8 +32,9 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) ngx_http_phase_handler_t tmp, *ph, *cur_ph, *last_ph; ngx_http_core_main_conf_t *cmcf; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua access handler, uri \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua access handler, uri:\"%V\" c:%ud", &r->uri, + r->main->count); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 1e0675b427..11deaee5bd 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -141,8 +141,9 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_int_t rc; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua content handler, uri \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua content handler, uri:\"%V\" c:%ud", &r->uri, + r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index ed3c14beff..08e9a19ca8 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -75,8 +75,9 @@ ngx_http_lua_log_handler(ngx_http_request_t *r) lua_State *L; ngx_http_lua_ctx_t *ctx; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua log handler, uri \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua log handler, uri:\"%V\" c:%ud", &r->uri, + r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t index 42117cdf00..bc00cae1bd 100644 --- a/t/079-unused-directives.t +++ b/t/079-unused-directives.t @@ -34,12 +34,12 @@ GET /t --- no_error_log lua capture header filter, uri "/t" lua capture body filter, uri "/t" -lua rewrite handler, uri "/t" -lua access handler, uri "/t" -lua content handler, uri "/t" +lua rewrite handler, uri:"/t" +lua access handler, uri:"/t" +lua content handler, uri:"/t" lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] @@ -59,11 +59,11 @@ lua rewrite handler, uri:"/t" lua capture header filter, uri "/t" lua capture body filter, uri "/t" --- no_error_log -lua access handler, uri "/t" -lua content handler, uri "/t" +lua access handler, uri:"/t" +lua content handler, uri:"/t" lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] --- log_level: debug @@ -80,15 +80,15 @@ GET /t --- response_body hello --- error_log -lua access handler, uri "/t" +lua access handler, uri:"/t" c:1 lua capture body filter, uri "/t" lua capture header filter, uri "/t" --- no_error_log -lua rewrite handler, uri "/t" -lua content handler, uri "/t" +lua rewrite handler, uri:"/t" +lua content handler, uri:"/t" lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] @@ -103,15 +103,15 @@ GET /t --- response_body hello --- error_log -lua content handler, uri "/t" +lua content handler, uri:"/t" c:1 lua capture body filter, uri "/t" lua capture header filter, uri "/t" --- no_error_log -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] @@ -130,11 +130,11 @@ hello lua header filter for user lua code, uri "/t" --- no_error_log lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" lua body filter for user lua code, uri "/t" [error] @@ -151,13 +151,13 @@ GET /t --- response_body hello --- error_log -lua log handler, uri "/t" +lua log handler, uri:"/t" --- no_error_log lua header filter for user lua code, uri "/t" lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" lua body filter for user lua code, uri "/t" [error] @@ -179,11 +179,11 @@ lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" --- no_error_log lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] @@ -205,11 +205,11 @@ hello lua header filter for user lua code, uri "/t" --- no_error_log lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" lua body filter for user lua code, uri "/t" [error] @@ -226,13 +226,13 @@ GET /t --- response_body hello --- error_log -lua log handler, uri "/t" +lua log handler, uri:"/t" --- no_error_log lua header filter for user lua code, uri "/t" lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" lua body filter for user lua code, uri "/t" [error] @@ -254,10 +254,10 @@ lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" --- no_error_log lua capture header filter, uri "/t" -lua content handler, uri "/t" -lua access handler, uri "/t" -lua rewrite handler, uri "/t" +lua content handler, uri:"/t" +lua access handler, uri:"/t" +lua rewrite handler, uri:"/t" lua capture body filter, uri "/t" -lua log handler, uri "/t" +lua log handler, uri:"/t" [error] From b5492eedbcc67365a5fb994727bf8f009696d242 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 15:58:03 -0800 Subject: [PATCH 0002/1981] fixed test cases using the deprecated math.mod() method. --- t/091-coroutine.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/091-coroutine.t b/t/091-coroutine.t index d582229e0b..0ce52f7e52 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -230,12 +230,12 @@ successfully connected to: openresty.org while 1 do local n = g() if n == nil then return end - if math.mod(n, p) ~= 0 then coroutine.yield(n) end + if math.fmod(n, p) ~= 0 then coroutine.yield(n) end end end) end - N = 10 + N = 10 x = gen(N) -- generate primes up to N while 1 do local n = x() -- pick a number until done @@ -276,7 +276,7 @@ GET /lua while 1 do local n = g() if n == nil then return end - if math.mod(n, p) ~= 0 then coroutine.yield(n) end + if math.fmod(n, p) ~= 0 then coroutine.yield(n) end end end) end From 49eab61c2386f1e350a952bd26c9b9fae2fe3cb2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 16:51:19 -0800 Subject: [PATCH 0003/1981] bugfix: the original Lua VM error messages might get lost in case of Lua code crashes when user coroutines were used. thanks Dirk Feytons for the report in github issue #208. --- src/ngx_http_lua_util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index d5f33e1f9c..337a06e5ec 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -970,7 +970,7 @@ ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int nret) { - ngx_http_lua_co_ctx_t *next_coctx, *parent_coctx; + ngx_http_lua_co_ctx_t *next_coctx, *parent_coctx, *orig_coctx; int rv, nrets, success = 1; lua_State *next_co; lua_State *old_co; @@ -1015,7 +1015,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, dd("ctx: %p", ctx); dd("cur co: %p", ctx->cur_co_ctx->co); - rv = lua_resume(ctx->cur_co_ctx->co, nrets); + orig_coctx = ctx->cur_co_ctx; + rv = lua_resume(orig_coctx->co, nrets); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -1297,6 +1298,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, break; } + if (ctx->cur_co_ctx != orig_coctx) { + ctx->cur_co_ctx = orig_coctx; + } + if (lua_isstring(ctx->cur_co_ctx->co, -1)) { dd("user custom error msg"); msg = lua_tostring(ctx->cur_co_ctx->co, -1); From 6f347161588a9c7d6c9b47db10a7606cac9621e4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 17:40:55 -0800 Subject: [PATCH 0004/1981] fixed a test case that may fail expectedly in slow testing mode. --- t/024-access/uthread-exit.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 302d2b7c47..122b250a5a 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -897,6 +897,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread From 414c6605ad7521d7506d2fc0fa236e0cf3355677 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 17:42:10 -0800 Subject: [PATCH 0005/1981] added a (passing) test for github issue #208: coroutine as iterator doesn't work --- t/091-coroutine.t | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 0ce52f7e52..92eab69288 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -923,3 +923,60 @@ status: running --- no_error_log [error] + + +=== TEST 23: github issue #208: coroutine as iterator doesn't work +--- config + location = /t { + content_by_lua ' + local say = ngx.say + local wrap, yield = coroutine.wrap, coroutine.yield + + local function it(it_state) + for i = 1, it_state.i do + yield(it_state.path, tostring(i)) + end + return nil + end + + local function it_factory(path) + local it_state = { i = 10, path = path } + return wrap(it), it_state + end + + --[[ + for path, value in it_factory("test") do + say(path, value) + end + ]] + + do + local f, s, var = it_factory("test") + while true do + local path, value = f(s, var) + var = path + if var == nil then break end + say(path, value) + end + end + '; + } +--- request + GET /t +--- more_headers +Cookie: abc=32 +--- stap2 eval: $::StapScript +--- response_body +test1 +test2 +test3 +test4 +test5 +test6 +test7 +test8 +test9 +test10 +--- no_error_log +[error] + From 96a18a054f0f960cf21080e12dd982627afbc3f7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 12 Feb 2013 17:13:37 -0800 Subject: [PATCH 0006/1981] fixed more test cases using systemtap that could fail expectedly in slow testing modes. --- t/023-rewrite/uthread-exit.t | 7 +++++++ t/024-access/uthread-exit.t | 6 ++++++ t/094-uthread-exit.t | 11 +++++++++++ 3 files changed, 24 insertions(+) diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index c270da1176..118564ca9b 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -297,6 +297,7 @@ delete thread 2 terminate 3: ok delete thread 3 +--- wait: 0.1 --- response_body before after @@ -916,6 +917,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1007,6 +1009,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1094,6 +1097,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1181,6 +1185,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1271,6 +1276,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log @@ -1365,6 +1371,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 122b250a5a..c6063c3f9f 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -297,6 +297,7 @@ delete thread 2 terminate 3: ok delete thread 3 +--- wait: 0.1 --- response_body before after @@ -989,6 +990,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1076,6 +1078,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1163,6 +1166,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1253,6 +1257,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log @@ -1347,6 +1352,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 593cfe0ab5..398172d880 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -285,6 +285,7 @@ delete thread 1 terminate 2: ok delete thread 2 +--- wait: 0.1 --- response_body before after @@ -867,6 +868,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body before hello in thread @@ -955,6 +957,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1039,6 +1042,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body before hello in thread @@ -1123,6 +1127,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- ignore_response --- error_log attempt to abort with pending subrequests @@ -1209,6 +1214,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body end --- error_log @@ -1300,6 +1306,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body end --- error_log @@ -1389,6 +1396,7 @@ delete thread 1 delete timer 200 free request +--- wait: 0.1 --- ignore_response --- error_log attempt to abort with pending subrequests @@ -1472,6 +1480,7 @@ delete thread 1 delete timer 200 free request +--- wait: 0.1 --- ignore_response --- no_error_log [alert] @@ -1554,6 +1563,7 @@ delete thread 1 delete timer 200 free request +--- wait: 0.1 --- ignore_response --- no_error_log [alert] @@ -1636,6 +1646,7 @@ delete thread 1 delete timer 200 free request +--- wait: 0.1 --- ignore_response --- no_error_log [alert] From 57a6471bf1e37c6a77006794920a40439bc7ed82 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 12 Feb 2013 21:59:26 -0800 Subject: [PATCH 0007/1981] updated docs to reflect recent changes; also bumped version to 0.7.15. --- README | 24 +++++++++++++++--------- README.markdown | 14 +++++++++----- doc/HttpLuaModule.wiki | 14 +++++++++----- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/README b/README index 40f212b819..fed5efcd05 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.14 - () released on 28 - January 2013. + This document describes ngx_lua v0.7.15 + () released on 12 + February 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -1255,13 +1255,15 @@ Directives context: *http, server, location, location-if* - Enables or disables response caching for HTTP 1.0 (or older) requests. - This buffering mechanism is mainly used for HTTP 1.0 keep-alive which - replies on a proper "Content-Length" response header. + Enables or disables automatic response buffering for HTTP 1.0 (or older) + requests. This buffering mechanism is mainly used for HTTP 1.0 + keep-alive which replies on a proper "Content-Length" response header. If the Lua code explicitly sets a "Content-Length" response header before sending the headers (either explicitly via ngx.send_headers or - implicitly via the first ngx.say or ngx.print call). + implicitly via the first ngx.say or ngx.print call), then the HTTP 1.0 + response buffering will be disabled even when this directive is turned + on. To output very large response data in a streaming fashion (via the ngx.flush call, for example), this directive MUST be turned off to @@ -2361,7 +2363,7 @@ Nginx API for Lua Removing the "max_args" cap is strongly discouraged. ngx.req.get_post_args - syntax: *ngx.req.get_post_args(max_args?)* + syntax: *args, err = ngx.req.get_post_args(max_args?)* context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** @@ -2369,12 +2371,16 @@ Nginx API for Lua Returns a Lua table holding all the current request POST query arguments (of the MIME type "application/x-www-form-urlencoded"). Call ngx.req.read_body to read the request body first or turn on the - lua_need_request_body directive to avoid Lua exception errors. + lua_need_request_body directive to avoid errors. location = /test { content_by_lua ' ngx.req.read_body() local args = ngx.req.get_post_args() + if not args then + ngx.say("failed to get post args: ", err) + return + end for key, val in pairs(args) do if type(val) == "table" then ngx.say(key, ": ", table.concat(val, ", ")) diff --git a/README.markdown b/README.markdown index b2a6f2bcff..e085b9e5ee 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.14](https://github.com/chaoslawful/lua-nginx-module/tags) released on 28 January 2013. +This document describes ngx_lua [v0.7.15](https://github.com/chaoslawful/lua-nginx-module/tags) released on 12 February 2013. Synopsis ======== @@ -1115,9 +1115,9 @@ lua_http10_buffering **context:** *http, server, location, location-if* -Enables or disables response caching for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper `Content-Length` response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper `Content-Length` response header. -If the Lua code explicitly sets a `Content-Length` response header before sending the headers (either explicitly via [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers) or implicitly via the first [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) or [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print) call). +If the Lua code explicitly sets a `Content-Length` response header before sending the headers (either explicitly via [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers) or implicitly via the first [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) or [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print) call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. To output very large response data in a streaming fashion (via the [ngx.flush](http://wiki.nginx.org/HttpLuaModule#ngx.flush) call, for example), this directive MUST be turned off to minimize memory usage. @@ -2193,17 +2193,21 @@ Removing the `max_args` cap is strongly discouraged. ngx.req.get_post_args --------------------- -**syntax:** *ngx.req.get_post_args(max_args?)* +**syntax:** *args, err = ngx.req.get_post_args(max_args?)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** -Returns a Lua table holding all the current request POST query arguments (of the MIME type `application/x-www-form-urlencoded`). Call [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) to read the request body first or turn on the [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) directive to avoid Lua exception errors. +Returns a Lua table holding all the current request POST query arguments (of the MIME type `application/x-www-form-urlencoded`). Call [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) to read the request body first or turn on the [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) directive to avoid errors. location = /test { content_by_lua ' ngx.req.read_body() local args = ngx.req.get_post_args() + if not args then + ngx.say("failed to get post args: ", err) + return + end for key, val in pairs(args) do if type(val) == "table" then ngx.say(key, ": ", table.concat(val, ", ")) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9297dfc7c3..07b06baeb2 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.14] released on 28 January 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.15] released on 12 February 2013. = Synopsis = @@ -1073,9 +1073,9 @@ This directive was first introduced in the v0.5.13 release. '''context:''' ''http, server, location, location-if'' -Enables or disables response caching for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper Content-Length response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper Content-Length response header. -If the Lua code explicitly sets a Content-Length response header before sending the headers (either explicitly via [[#ngx.send_headers|ngx.send_headers]] or implicitly via the first [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] call). +If the Lua code explicitly sets a Content-Length response header before sending the headers (either explicitly via [[#ngx.send_headers|ngx.send_headers]] or implicitly via the first [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. To output very large response data in a streaming fashion (via the [[#ngx.flush|ngx.flush]] call, for example), this directive MUST be turned off to minimize memory usage. @@ -2127,17 +2127,21 @@ This argument can be set to zero to remove the limit and to process all request Removing the max_args cap is strongly discouraged. == ngx.req.get_post_args == -'''syntax:''' ''ngx.req.get_post_args(max_args?)'' +'''syntax:''' ''args, err = ngx.req.get_post_args(max_args?)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' -Returns a Lua table holding all the current request POST query arguments (of the MIME type application/x-www-form-urlencoded). Call [[#ngx.req.read_body|ngx.req.read_body]] to read the request body first or turn on the [[#lua_need_request_body|lua_need_request_body]] directive to avoid Lua exception errors. +Returns a Lua table holding all the current request POST query arguments (of the MIME type application/x-www-form-urlencoded). Call [[#ngx.req.read_body|ngx.req.read_body]] to read the request body first or turn on the [[#lua_need_request_body|lua_need_request_body]] directive to avoid errors. location = /test { content_by_lua ' ngx.req.read_body() local args = ngx.req.get_post_args() + if not args then + ngx.say("failed to get post args: ", err) + return + end for key, val in pairs(args) do if type(val) == "table" then ngx.say(key, ": ", table.concat(val, ", ")) From e9dd32848964008cc51e98424aad21b25757ca4c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Feb 2013 11:33:20 -0800 Subject: [PATCH 0008/1981] minor optimizations in the script engine to save a little memory. --- src/ngx_http_lua_script.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ngx_http_lua_script.c b/src/ngx_http_lua_script.c index 410b77b829..5e847fb89a 100644 --- a/src/ngx_http_lua_script.c +++ b/src/ngx_http_lua_script.c @@ -69,7 +69,6 @@ ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv) n = (nv * (2 * sizeof(ngx_http_lua_script_copy_code_t) + sizeof(ngx_http_lua_script_copy_capture_code_t)) + sizeof(uintptr_t) - + v->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); @@ -493,7 +492,6 @@ ngx_http_lua_script_init_arrays(ngx_http_lua_script_compile_t *sc) n = (sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t) + sizeof(ngx_http_lua_script_copy_capture_code_t)) + sizeof(uintptr_t) - + sc->source->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); From 4beec04baab10576ac66cd5bd61c946db8ef17f3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Feb 2013 11:39:49 -0800 Subject: [PATCH 0009/1981] added (passing) tests for using $0 in the replacement template when no capturing parenthese are used in the regexes. --- t/036-sub.t | 21 ++++++++++++++++++++- t/037-gsub.t | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/t/036-sub.t b/t/036-sub.t index b266a75b68..60727ab0d3 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 1); #no_diff(); no_long_string(); @@ -426,3 +426,22 @@ a [b c] [b] [c] [] [] d --- no_error_log [error] + + +=== TEST 23: $0 without parens +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("a b c d", [[\w]], "[$0]") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +[a] b c d +1 +--- no_error_log +[error] + diff --git a/t/037-gsub.t b/t/037-gsub.t index 8143406816..7b9bf3055d 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 9); #no_diff(); no_long_string(); @@ -384,3 +384,22 @@ n: 1 [hello,h], [world,w] 2 + + +=== TEST 19: $0 without parens +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("a b c d", [[\w]], "[$0]") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +[a] [b] [c] [d] +4 +--- no_error_log +[error] + From 5d114acb421a5883d1cca8ba35541495cca94714 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Feb 2013 11:41:51 -0800 Subject: [PATCH 0010/1981] optimize: removed the unsed "size" field and related computatins from the script engine. --- src/ngx_http_lua_script.c | 3 --- src/ngx_http_lua_script.h | 1 - 2 files changed, 4 deletions(-) diff --git a/src/ngx_http_lua_script.c b/src/ngx_http_lua_script.c index 5e847fb89a..a7dbb0c53a 100644 --- a/src/ngx_http_lua_script.c +++ b/src/ngx_http_lua_script.c @@ -185,7 +185,6 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) name.data = &sc->source->data[i]; i++; name.len++; - sc->size += name.len; if (ngx_http_lua_script_add_copy_code(sc, &name, (i == sc->source->len)) @@ -296,8 +295,6 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) name.len++; } - sc->size += name.len; - if (ngx_http_lua_script_add_copy_code(sc, &name, (i == sc->source->len)) != NGX_OK) { diff --git a/src/ngx_http_lua_script.h b/src/ngx_http_lua_script.h index 35410a2539..8c7f3aef5e 100644 --- a/src/ngx_http_lua_script.h +++ b/src/ngx_http_lua_script.h @@ -20,7 +20,6 @@ typedef struct { ngx_array_t **values; ngx_uint_t variables; - ngx_uint_t size; unsigned complete_lengths:1; unsigned complete_values:1; From 85841a721f4079ba7ab6fabfd748438291bbf3f4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Feb 2013 11:44:57 -0800 Subject: [PATCH 0011/1981] refactor: renamed ngx_http_lua_script_copy_capture_code_t to ngx_http_lua_script_capture_code_t. --- src/ngx_http_lua_script.c | 28 +++++++++++++--------------- src/ngx_http_lua_script.h | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/ngx_http_lua_script.c b/src/ngx_http_lua_script.c index a7dbb0c53a..ede04de0ba 100644 --- a/src/ngx_http_lua_script.c +++ b/src/ngx_http_lua_script.c @@ -59,7 +59,7 @@ ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv) } n = nv * (2 * sizeof(ngx_http_lua_script_copy_code_t) - + sizeof(ngx_http_lua_script_copy_capture_code_t)) + + sizeof(ngx_http_lua_script_capture_code_t)) + sizeof(uintptr_t); if (ngx_array_init(&lengths, ccv->pool, n, 1) != NGX_OK) { @@ -67,7 +67,7 @@ ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv) } n = (nv * (2 * sizeof(ngx_http_lua_script_copy_code_t) - + sizeof(ngx_http_lua_script_copy_capture_code_t)) + + sizeof(ngx_http_lua_script_capture_code_t)) + sizeof(uintptr_t) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); @@ -391,10 +391,10 @@ static ngx_int_t ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, ngx_uint_t n) { - ngx_http_lua_script_copy_capture_code_t *code; + ngx_http_lua_script_capture_code_t *code; code = ngx_http_lua_script_add_code(*sc->lengths, - sizeof(ngx_http_lua_script_copy_capture_code_t)); + sizeof(ngx_http_lua_script_capture_code_t)); if (code == NULL) { return NGX_ERROR; } @@ -404,7 +404,7 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, code->n = 2 * n; code = ngx_http_lua_script_add_code(*sc->values, - sizeof(ngx_http_lua_script_copy_capture_code_t)); + sizeof(ngx_http_lua_script_capture_code_t)); if (code == NULL) { return NGX_ERROR; } @@ -421,12 +421,11 @@ ngx_http_lua_script_copy_capture_len_code(ngx_http_lua_script_engine_t *e) { int *cap; ngx_uint_t n; + ngx_http_lua_script_capture_code_t *code; - ngx_http_lua_script_copy_capture_code_t *code; + code = (ngx_http_lua_script_capture_code_t *) e->ip; - code = (ngx_http_lua_script_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_http_lua_script_copy_capture_code_t); + e->ip += sizeof(ngx_http_lua_script_capture_code_t); n = code->n; @@ -445,12 +444,11 @@ ngx_http_lua_script_copy_capture_code(ngx_http_lua_script_engine_t *e) int *cap; u_char *p, *pos; ngx_uint_t n; + ngx_http_lua_script_capture_code_t *code; - ngx_http_lua_script_copy_capture_code_t *code; - - code = (ngx_http_lua_script_copy_capture_code_t *) e->ip; + code = (ngx_http_lua_script_capture_code_t *) e->ip; - e->ip += sizeof(ngx_http_lua_script_copy_capture_code_t); + e->ip += sizeof(ngx_http_lua_script_capture_code_t); n = code->n; @@ -476,7 +474,7 @@ ngx_http_lua_script_init_arrays(ngx_http_lua_script_compile_t *sc) if (*sc->lengths == NULL) { n = sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t) - + sizeof(ngx_http_lua_script_copy_capture_code_t)) + + sizeof(ngx_http_lua_script_capture_code_t)) + sizeof(uintptr_t); *sc->lengths = ngx_array_create(sc->pool, n, 1); @@ -487,7 +485,7 @@ ngx_http_lua_script_init_arrays(ngx_http_lua_script_compile_t *sc) if (*sc->values == NULL) { n = (sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t) - + sizeof(ngx_http_lua_script_copy_capture_code_t)) + + sizeof(ngx_http_lua_script_capture_code_t)) + sizeof(uintptr_t) + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); diff --git a/src/ngx_http_lua_script.h b/src/ngx_http_lua_script.h index 8c7f3aef5e..3e66afdc27 100644 --- a/src/ngx_http_lua_script.h +++ b/src/ngx_http_lua_script.h @@ -71,7 +71,7 @@ typedef struct { typedef struct { ngx_http_lua_script_code_pt code; uintptr_t n; -} ngx_http_lua_script_copy_capture_code_t; +} ngx_http_lua_script_capture_code_t; ngx_int_t ngx_http_lua_compile_complex_value( From eb2d846311632e06db1a51d5af5c6d6a062ed1cd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 18 Feb 2013 12:07:27 -0800 Subject: [PATCH 0012/1981] fixed test cases in uthread-spawn.t for slow testing modes. --- t/023-rewrite/uthread-spawn.t | 1 + t/024-access/uthread-spawn.t | 1 + t/093-uthread-spawn.t | 1 + 3 files changed, 3 insertions(+) diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index e34a27783e..fffa96f9dc 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -204,6 +204,7 @@ delete thread 2 terminate 4: ok delete thread 4 +--- wait: 0.1 --- response_body 1: before thread create 1: before sleep diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index 50f3c8cfbe..c7086a88e1 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -204,6 +204,7 @@ delete thread 2 terminate 4: ok delete thread 4 +--- wait: 0.1 --- response_body 1: before thread create 1: before sleep diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 8b281ae676..376dba5b0b 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -182,6 +182,7 @@ delete thread 3 terminate 2: ok delete thread 2 +--- wait: 0.1 --- response_body 1: before thread create 1: before sleep From e30ea025c3207dbbe1d3690c305f7bade6d4ad42 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 22 Feb 2013 22:43:34 -0800 Subject: [PATCH 0013/1981] updated docs to reflect recent changes. --- README | 32 +++++++++++--------------------- README.markdown | 13 ++++++------- doc/HttpLuaModule.wiki | 13 ++++++------- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/README b/README index fed5efcd05..5efa1a1d30 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.15 - () released on 12 + This document describes ngx_lua v0.7.16 + () released on 22 February 2013. Synopsis @@ -5317,17 +5317,6 @@ Known Issues appears to affect Mac OS X. Lua Coroutine Yielding/Resuming - * As the module's predefined Nginx I/O API uses the coroutine - yielding/resuming mechanism, user code should not call any Lua - modules that use the Lua coroutine mechanism in order to prevent - conflicts with the module's predefined Nginx API methods such as - ngx.location.capture (Actually, coroutine modules have been masked - off in content_by_lua directives and others). This limitation is - significant and work is ongoing on an alternative coroutine - implementation that can fit into the Nginx event model to address - this. When this is done, it will be possible to use the Lua - coroutine mechanism freely as it is in standard Lua implementations. - * Lua's "dofile" builtin is implemented as a C function in both Lua 5.1 and LuaJIT 2.0 and when ngx.location.capture is called, ngx.exec, ngx.exit or ngx.req.read_body or similar in the file to be @@ -5343,10 +5332,11 @@ Known Issues ngx.redirect, ngx.exec, and ngx.exit cannot be used within the context of a Lua pcall() () or xpcall() - () when the - standard Lua 5.1 interpreter is used and the "attempt to yield - across metamethod/C-call boundary" error will be produced. Please - use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. + () or even the + first line of the "for ... in ..." statement when the standard Lua + 5.1 interpreter is used and the "attempt to yield across + metamethod/C-call boundary" error will be produced. Please use + LuaJIT 2.0, which supports a fully resumable VM, to avoid this. Lua Variable Scope Care must be taken when importing modules and this form should be used: @@ -5540,7 +5530,7 @@ Nginx Compatibility * 1.3.x (last tested: 1.3.11) - * 1.2.x (last tested: 1.2.6) + * 1.2.x (last tested: 1.2.7) * 1.1.x (last tested: 1.1.5) @@ -5581,9 +5571,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' - tar -xzvf nginx-1.2.6.tar.gz - cd nginx-1.2.6/ + wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' + tar -xzvf nginx-1.2.7.tar.gz + cd nginx-1.2.7/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/README.markdown b/README.markdown index e085b9e5ee..9ae5f0b417 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.15](https://github.com/chaoslawful/lua-nginx-module/tags) released on 12 February 2013. +This document describes ngx_lua [v0.7.16](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 February 2013. Synopsis ======== @@ -4726,9 +4726,8 @@ This issue is due to limitations in the Nginx event model and only appears to af Lua Coroutine Yielding/Resuming ------------------------------- -* As the module's predefined Nginx I/O API uses the coroutine yielding/resuming mechanism, user code should not call any Lua modules that use the Lua coroutine mechanism in order to prevent conflicts with the module's predefined Nginx API methods such as [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) (Actually, coroutine modules have been masked off in [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) directives and others). This limitation is significant and work is ongoing on an alternative coroutine implementation that can fit into the Nginx event model to address this. When this is done, it will be possible to use the Lua coroutine mechanism freely as it is in standard Lua implementations. * Lua's `dofile` builtin is implemented as a C function in both Lua 5.1 and LuaJIT 2.0 and when [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) is called, [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) or [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) or similar in the file to be loaded by `dofile`, a coroutine yield across the C function boundary will be initiated. This however is not normally allowed within ngx_lua and will usually result in error messages like `lua handler aborted: runtime error: attempt to yield across C-call boundary`. To avoid this, define a real Lua module and use the Lua `require` builtin instead. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture), [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi), [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), and [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture), [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi), [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), and [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. Lua Variable Scope ------------------ @@ -4894,7 +4893,7 @@ Nginx Compatibility The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.6) +* 1.2.x (last tested: 1.2.7) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -4920,9 +4919,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' - tar -xzvf nginx-1.2.6.tar.gz - cd nginx-1.2.6/ + wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' + tar -xzvf nginx-1.2.7.tar.gz + cd nginx-1.2.7/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 07b06baeb2..e546cf28b1 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.15] released on 12 February 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.16] released on 22 February 2013. = Synopsis = @@ -4565,9 +4565,8 @@ However, later attempts to manipulate the cosocket object will fail and return t This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. == Lua Coroutine Yielding/Resuming == -* As the module's predefined Nginx I/O API uses the coroutine yielding/resuming mechanism, user code should not call any Lua modules that use the Lua coroutine mechanism in order to prevent conflicts with the module's predefined Nginx API methods such as [[#ngx.location.capture|ngx.location.capture]] (Actually, coroutine modules have been masked off in [[#content_by_lua|content_by_lua]] directives and others). This limitation is significant and work is ongoing on an alternative coroutine implementation that can fit into the Nginx event model to address this. When this is done, it will be possible to use the Lua coroutine mechanism freely as it is in standard Lua implementations. * Lua's dofile builtin is implemented as a C function in both Lua 5.1 and LuaJIT 2.0 and when [[#ngx.location.capture|ngx.location.capture]] is called, [[#ngx.exec|ngx.exec]], [[#ngx.exit|ngx.exit]] or [[#ngx.req.read_body|ngx.req.read_body]] or similar in the file to be loaded by dofile, a coroutine yield across the C function boundary will be initiated. This however is not normally allowed within ngx_lua and will usually result in error messages like lua handler aborted: runtime error: attempt to yield across C-call boundary. To avoid this, define a real Lua module and use the Lua require builtin instead. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] or even the first line of the for ... in ... statement when the standard Lua 5.1 interpreter is used and the attempt to yield across metamethod/C-call boundary error will be produced. Please use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. == Lua Variable Scope == Care must be taken when importing modules and this form should be used: @@ -4728,7 +4727,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.6) +* 1.2.x (last tested: 1.2.7) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -4752,9 +4751,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' - tar -xzvf nginx-1.2.6.tar.gz - cd nginx-1.2.6/ + wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' + tar -xzvf nginx-1.2.7.tar.gz + cd nginx-1.2.7/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From 40fabb23bb32ce67ce0f1602277ffd0f3e87d607 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 28 Feb 2013 16:49:46 -0800 Subject: [PATCH 0014/1981] bugfix: ngx.re.match: when the "D" regex option was specified, an empty Lua table would always be created even when the named capture was actually empty. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_regex.c | 37 ++++++++++++++++++++++++------------- t/034-match.t | 26 +++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index d1c5af1bb3..2f9bd2aadc 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1902,13 +1902,21 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, char *name; for (i = 0; i < name_count; i++) { + dd("top: %d", lua_gettop(L)); name_entry = &name_table[i * name_entry_size]; n = (name_entry[0] << 8) | name_entry[1]; name = (char *) &name_entry[2]; + lua_rawgeti(L, -1, n); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + continue; + } + if (flags & NGX_LUA_RE_MODE_DUPNAMES) { - lua_getfield(L, -1, name); + + lua_getfield(L, -2, name); /* big_tb cap small_tb */ if (lua_isnil(L, -1)) { lua_pop(L, 1); @@ -1916,23 +1924,26 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, /* assuming named submatches are usually unique */ lua_createtable(L, 1 /* narr */, 0 /* nrec */); lua_pushstring(L, name); - lua_pushvalue(L, -2); /* big_tb small_tb key small_tb */ - lua_rawset(L, -4); /* big_tb small_tb */ - } - - len = lua_objlen(L, -1); + lua_pushvalue(L, -2); /* big_tb cap small_tb key small_tb */ + lua_rawset(L, -5); /* big_tb cap small_tb */ + len = 0; - lua_rawgeti(L, -2, n); - lua_rawseti(L, -2, (int) len + 1); + } else { + len = lua_objlen(L, -1); + } - /* pop the m[name] array we pulled in */ - lua_pop(L, 1); + lua_pushvalue(L, -2); /* big_tb cap small_tb cap */ + lua_rawseti(L, -2, (int) len + 1); /* big_tb cap small_tb */ + lua_pop(L, 2); } else { - lua_pushstring(L, name); - lua_rawgeti(L, -2, n); - lua_rawset(L, -3); + lua_pushstring(L, name); /* big_tb cap key */ + lua_pushvalue(L, -2); /* big_tb cap key cap */ + lua_rawset(L, -4); /* big_tb cap */ + lua_pop(L, 1); } + + dd("top 2: %d", lua_gettop(L)); } } diff --git a/t/034-match.t b/t/034-match.t index 9273abe6e1..65d5bd8142 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 8); #no_diff(); no_long_string(); @@ -878,3 +878,27 @@ matched: 章 --- no_error_log [error] + + +=== TEST 41: empty duplicate captures +--- config + location = /t { + content_by_lua " + local target = 'test' + local regex = '^(?:(?(?:foo))|(?(?:bar))|(?(?:test)))$' + + -- Note the D here + local m = ngx.re.match(target, regex, 'D') + + ngx.say(type(m.group1)) + ngx.say(type(m.group2)) + "; + } +--- request +GET /t +--- response_body +nil +nil +--- no_error_log +[error] + From eff99d5dba8351dd4afb464b1fb97804eedf63db Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 4 Mar 2013 17:29:00 -0800 Subject: [PATCH 0015/1981] bugfix: use of ngx.req.socket() could make socket reading hang infinitely when the request did not take a request body at all (that is, when the Content-Length request header is missing). thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_socket_tcp.c | 6 ++- t/023-rewrite/uthread-exit.t | 4 ++ t/024-access/uthread-exit.t | 5 ++ t/066-socket-receiveuntil.t | 4 +- t/067-req-socket.t | 86 +++++++++++++++++++++++++++++++++++ t/083-bad-sock-self.t | 6 ++- t/094-uthread-exit.t | 3 ++ 7 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5a5070dafd..12e8b759a0 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3032,9 +3032,11 @@ ngx_http_lua_req_socket(lua_State *L) return 2; } - if (r->headers_in.content_length_n == 0) { + dd("req content length: %d", (int) r->headers_in.content_length_n); + + if (r->headers_in.content_length_n <= 0) { lua_pushnil(L); - lua_pushliteral(L, "request body empty"); + lua_pushliteral(L, "no body"); return 2; } diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index 118564ca9b..e14b85c5b5 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -956,6 +956,10 @@ after } --- request POST /lua + +--- more_headers +Content-Length: 1024 + --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index c6063c3f9f..5d19eb6619 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -165,6 +165,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body before hello in thread @@ -937,6 +938,10 @@ after } --- request POST /lua + +--- more_headers +Content-Length: 1024 + --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 9d6c7c0f8f..2570a9382b 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1323,7 +1323,9 @@ this exposed a memory leak in receiveuntil '; } --- request - GET /t + POST /t + +--- more_headers: Content-Length: 1024 --- response_body ok --- no_error_log diff --git a/t/067-req-socket.t b/t/067-req-socket.t index d6d2aa0197..542e4e13e4 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -666,3 +666,89 @@ hello world [alert] --- skip_nginx: 4: <1.3.9 + + +=== TEST 11: downstream cosocket for GET requests (w/o request bodies) +--- config + #resolver 8.8.8.8; + location = /t { + content_by_lua ' + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + while true do + local data, err, partial = sock:receive(4096) + + ngx.log(ngx.INFO, "Received data") + + if err then + ngx.say("err: ", err) + if partial then + ngx.print(partial) + end + + break + end + + if data then + ngx.print(data) + end + end + '; + } + +--- request +GET /t +--- response_body +failed to get socket: no body +--- no_error_log +[error] + + + +=== TEST 12: downstream cosocket for POST requests with 0 size bodies +--- config + #resolver 8.8.8.8; + location = /t { + content_by_lua ' + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + while true do + local data, err, partial = sock:receive(4096) + + ngx.log(ngx.INFO, "Received data") + + if err then + ngx.say("err: ", err) + if partial then + ngx.print(partial) + end + + break + end + + if data then + ngx.print(data) + end + end + '; + } + +--- request +POST /t +--- more_headers +Content-Length: 0 +--- response_body +failed to get socket: no body +--- no_error_log +[error] + diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t index 50b9cdd921..37b65ef2ed 100644 --- a/t/083-bad-sock-self.t +++ b/t/083-bad-sock-self.t @@ -28,7 +28,8 @@ __DATA__ '; } --- request - GET /t + POST /t +--- more_headers: Content-Length: 1024 --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log @@ -45,7 +46,8 @@ bad argument #1 to 'receive' (table expected, got string) '; } --- request - GET /t + POST /t +--- more_headers: Content-Length: 1024 --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 398172d880..88a24507cd 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -906,6 +906,9 @@ after } --- request POST /lua +--- more_headers +Content-Length: 1024 + --- stap2 eval: $::StapScript --- stap eval <<'_EOC_' . $::GCScript; From 76910a32d24aecb0b7b4bf7d7982b0f93a9fe249 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 4 Mar 2013 22:20:32 -0800 Subject: [PATCH 0016/1981] fixed tests that may fail in slow testing modes. --- t/024-access/uthread-exec.t | 1 + t/096-uthread-redirect.t | 1 + 2 files changed, 2 insertions(+) diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 10982a60f6..90e4ddcdde 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -168,6 +168,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body hello foo --- no_error_log diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 8a756ed45d..0a655d74ab 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -105,6 +105,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body end --- error_log From 5361c952997117a7496796371300884859600a80 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 4 Mar 2013 22:22:57 -0800 Subject: [PATCH 0017/1981] bugfix: ngx.req.get_headers(limit, true) would still return header names in the all-lower-case form when the "limit" argument was an integer. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_headers.c | 1 - t/028-req-header.t | 28 +++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 6ed984e00c..cb459e2d5b 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -44,7 +44,6 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { } else { max = luaL_checkinteger(L, 1); - lua_pop(L, 1); } if (n >= 2) { diff --git a/t/028-req-header.t b/t/028-req-header.t index e916e05fab..4875b5aa7c 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => (2 * blocks() + 5) * repeat_each(); +plan tests => (2 * blocks() + 6) * repeat_each(); #no_diff(); no_long_string(); @@ -1037,3 +1037,29 @@ foo-21: 21\r " + + +=== TEST 34: raw form +--- config + location /t { + content_by_lua ' + -- get ALL the raw headers (0 == no limit, not recommended) + local headers = ngx.req.get_headers(0, true) + for k, v in pairs(headers) do + ngx.say{ k, ": ", v} + end + '; + } +--- request +GET /t +--- more_headers +My-Foo: bar +Bar: baz +--- response_body +Host: localhost +Bar: baz +My-Foo: bar +Connection: Close +--- no_error_log +[error] + From 89861df1c300087fa90d51c4f1a097a35314720c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 5 Mar 2013 15:59:57 -0800 Subject: [PATCH 0018/1981] feature: implemented ngx.req.http_version() that returns the HTTP version number for the current request. thanks Matthieu Tourne for requesting this. --- README | 13 ++++++++++ README.markdown | 12 +++++++++ doc/HttpLuaModule.wiki | 11 +++++++++ src/ngx_http_lua_headers.c | 40 ++++++++++++++++++++++++++++++ src/ngx_http_lua_util.c | 2 +- t/062-count.t | 6 ++--- t/103-req-http-ver.t | 50 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 t/103-req-http-ver.t diff --git a/README b/README index 5efa1a1d30..24e144f50d 100644 --- a/README +++ b/README @@ -2141,6 +2141,19 @@ Nginx API for Lua See also ngx.now and ngx.update_time. + ngx.req.http_version + syntax: *num = ngx.req.http_version()* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua** + + Returns the HTTP version number for the current request as a Lua number. + + Current possible values are 1.0, 1.1, and 0.9. Returns "nil" for + unrecognized values. + + This method was first introduced in the "v0.7.17" release. + ngx.req.get_method syntax: *method_name = ngx.req.get_method()* diff --git a/README.markdown b/README.markdown index 9ae5f0b417..553b340996 100644 --- a/README.markdown +++ b/README.markdown @@ -1959,6 +1959,18 @@ This function was first introduced in the `v0.7.7` release. See also [ngx.now](http://wiki.nginx.org/HttpLuaModule#ngx.now) and [ngx.update_time](http://wiki.nginx.org/HttpLuaModule#ngx.update_time). +ngx.req.http_version +-------------------- +**syntax:** *num = ngx.req.http_version()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** + +Returns the HTTP version number for the current request as a Lua number. + +Current possible values are 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. + +This method was first introduced in the `v0.7.17` release. + ngx.req.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index e546cf28b1..e9df0c7999 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1899,6 +1899,17 @@ This function was first introduced in the v0.7.7 release. See also [[#ngx.now|ngx.now]] and [[#ngx.update_time|ngx.update_time]]. +== ngx.req.http_version == +'''syntax:''' ''num = ngx.req.http_version()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*'' + +Returns the HTTP version number for the current request as a Lua number. + +Current possible values are 1.0, 1.1, and 0.9. Returns nil for unrecognized values. + +This method was first introduced in the v0.7.17 release. + == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index cb459e2d5b..1b39a2564a 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -17,6 +17,7 @@ #include "ngx_http_lua_util.h" +static int ngx_http_lua_ngx_req_http_version(lua_State *L); static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L); static int ngx_http_lua_ngx_header_get(lua_State *L); static int ngx_http_lua_ngx_header_set(lua_State *L); @@ -25,6 +26,42 @@ static int ngx_http_lua_ngx_req_header_clear(lua_State *L); static int ngx_http_lua_ngx_req_header_set(lua_State *L); +static int +ngx_http_lua_ngx_req_http_version(lua_State *L) +{ + ngx_http_request_t *r; + + lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_rawget(L, LUA_GLOBALSINDEX); + r = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + + switch (r->http_version) { + case NGX_HTTP_VERSION_9: + lua_pushnumber(L, 0.9); + break; + + case NGX_HTTP_VERSION_10: + lua_pushnumber(L, 1.0); + break; + + case NGX_HTTP_VERSION_11: + lua_pushnumber(L, 1.1); + break; + + default: + lua_pushnil(L); + break; + } + + return 1; +} + + static int ngx_http_lua_ngx_req_get_headers(lua_State *L) { ngx_list_part_t *part; @@ -466,6 +503,9 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) { int rc; + lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version); + lua_setfield(L, -2, "http_version"); + lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear); lua_setfield(L, -2, "clear_header"); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 337a06e5ec..ce55b68314 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2005,7 +2005,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 21 /* nrec */); /* .req */ + lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* .req */ ngx_http_lua_inject_req_header_api(log, L); ngx_http_lua_inject_req_uri_api(log, L); diff --git a/t/062-count.t b/t/062-count.t index a5dbb2025d..8b1bcd8893 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -124,7 +124,7 @@ n = 1 --- request GET /test --- response_body -n = 21 +n = 22 --- no_error_log [error] @@ -146,7 +146,7 @@ n = 21 --- request GET /test --- response_body -n = 21 +n = 22 --- no_error_log [error] @@ -173,7 +173,7 @@ n = 21 --- request GET /test --- response_body -n = 21 +n = 22 --- no_error_log [error] diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t new file mode 100644 index 0000000000..126f00a1bb --- /dev/null +++ b/t/103-req-http-ver.t @@ -0,0 +1,50 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); +#repeat_each(1); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: HTTP 1.1 +--- config + location /t { + content_by_lua ' + ngx.say(ngx.req.http_version()) + '; + } +--- request +GET /t +--- response_body +1.1 +--- no_error_log +[error] + + + +=== TEST 2: HTTP 1.0 +--- config + location /t { + content_by_lua ' + ngx.say(ngx.req.http_version()) + '; + } +--- request +GET /t HTTP/1.0 +--- response_body +1 +--- no_error_log +[error] + From 4927e75b0507477f425a7296cf44119453363b2d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 6 Mar 2013 16:01:55 -0800 Subject: [PATCH 0019/1981] fixed a typo in an error message. thanks Matthieu Tourne for reporting it. --- src/ngx_http_lua_variable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index 98c0c152f1..2864ce6519 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -273,7 +273,7 @@ ngx_http_lua_var_set(lua_State *L) /* variable not found */ - return luaL_error(L, "varaible \"%s\" not found for writing; " + return luaL_error(L, "variable \"%s\" not found for writing; " "maybe it is a built-in variable that is not changeable " "or you forgot to use \"set $%s '';\" " "in the config file to define it first", From c95456c872023dd33688943b90d0bff283b0b117 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 6 Mar 2013 17:14:12 -0800 Subject: [PATCH 0020/1981] feature: implemented the ngx.req.raw_header() function for returning the original raw HTTP protocol header string received by Nginx. thanks Matthieu Tourne for requesting this. --- README | 34 ++++ README.markdown | 42 +++++ doc/HttpLuaModule.wiki | 41 +++++ src/ngx_http_lua_headers.c | 170 ++++++++++++++++++ src/ngx_http_lua_util.c | 2 +- t/062-count.t | 6 +- t/104-req-raw-header.t | 359 +++++++++++++++++++++++++++++++++++++ 7 files changed, 650 insertions(+), 4 deletions(-) create mode 100644 t/104-req-raw-header.t diff --git a/README b/README index 24e144f50d..ae1329f78d 100644 --- a/README +++ b/README @@ -2154,6 +2154,40 @@ Nginx API for Lua This method was first introduced in the "v0.7.17" release. + ngx.req.raw_header + syntax: *str = ngx.req.raw_header(no_request_line?)* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua** + + Returns the original raw HTTP protocol header received by the Nginx + server. + + By default, the request line and trailing "CR LF" terminator will also + be included. For example, + + ngx.print(ngx.req.raw_header()) + + gives something like this: + + GET /t HTTP/1.1 + Host: localhost + Connection: close + Foo: bar + + You can specify the optional "no_request_line" argument as a "true" + value to exclude the request line from the result. For example, + + ngx.print(ngx.req.raw_header(true)) + + outputs something like this: + + Host: localhost + Connection: close + Foo: bar + + This method was first introduced in the "v0.7.17" release. + ngx.req.get_method syntax: *method_name = ngx.req.get_method()* diff --git a/README.markdown b/README.markdown index 553b340996..cc3b4949f8 100644 --- a/README.markdown +++ b/README.markdown @@ -1969,6 +1969,48 @@ Returns the HTTP version number for the current request as a Lua number. Current possible values are 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values. +This method was first introduced in the `v0.7.17` release. + +ngx.req.raw_header +------------------ +**syntax:** *str = ngx.req.raw_header(no_request_line?)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua** + +Returns the original raw HTTP protocol header received by the Nginx server. + +By default, the request line and trailing `CR LF` terminator will also be included. For example, + + + ngx.print(ngx.req.raw_header()) + + +gives something like this: + + + GET /t HTTP/1.1 + Host: localhost + Connection: close + Foo: bar + + + +You can specify the optional +`no_request_line` argument as a `true` value to exclude the request line from the result. For example, + + + ngx.print(ngx.req.raw_header(true)) + + +outputs something like this: + + + Host: localhost + Connection: close + Foo: bar + + + This method was first introduced in the `v0.7.17` release. ngx.req.get_method diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index e9df0c7999..4e871b734c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1910,6 +1910,47 @@ Current possible values are 1.0, 1.1, and 0.9. Returns nil for unre This method was first introduced in the v0.7.17 release. +== ngx.req.raw_header == +'''syntax:''' ''str = ngx.req.raw_header(no_request_line?)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*'' + +Returns the original raw HTTP protocol header received by the Nginx server. + +By default, the request line and trailing CR LF terminator will also be included. For example, + + + ngx.print(ngx.req.raw_header()) + + +gives something like this: + + + GET /t HTTP/1.1 + Host: localhost + Connection: close + Foo: bar + + + +You can specify the optional +no_request_line argument as a true value to exclude the request line from the result. For example, + + + ngx.print(ngx.req.raw_header(true)) + + +outputs something like this: + + + Host: localhost + Connection: close + Foo: bar + + + +This method was first introduced in the v0.7.17 release. + == ngx.req.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 1b39a2564a..ce552ddc42 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -18,6 +18,7 @@ static int ngx_http_lua_ngx_req_http_version(lua_State *L); +static int ngx_http_lua_ngx_req_raw_header(lua_State *L); static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L); static int ngx_http_lua_ngx_header_get(lua_State *L); static int ngx_http_lua_ngx_header_set(lua_State *L); @@ -62,6 +63,172 @@ ngx_http_lua_ngx_req_http_version(lua_State *L) } +static int +ngx_http_lua_ngx_req_raw_header(lua_State *L) +{ + int n; + u_char *data, *p, *last; + unsigned no_req_line = 0, found; + size_t size; + ngx_buf_t *b, *first = NULL; + ngx_int_t i; + ngx_http_request_t *r; + ngx_http_connection_t *hc; + + n = lua_gettop(L); + if (n > 0) { + no_req_line = lua_toboolean(L, 1); + } + + dd("no req line: %d", (int) no_req_line); + + lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_rawget(L, LUA_GLOBALSINDEX); + r = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + + hc = r->http_connection; + + if (hc->nbusy) { + b = NULL; /* to suppress a gcc warning */ + size = 0; + for (i = 0; i < hc->nbusy; i++) { + b = hc->busy[i]; + + if (first == NULL) { + if (r->request_line.data >= b->pos + || r->request_line.data + r->request_line.len + 2 + <= b->start) + { + continue; + } + + dd("found first at %d", (int) i); + first = b; + } + + size += b->pos - b->start; + + if (b == r->header_in) { + break; + } + } + + } else { + if (r != r->main) { + b = r->main->header_in; + + } else { + b = r->header_in; + } + + if (b == NULL) { + lua_pushnil(L); + return 1; + } + + size = b->pos - r->request_line.data; + } + + data = lua_newuserdata(L, size); + + if (hc->nbusy) { + last = data; + found = 0; + for (i = 0; i < hc->nbusy; i++) { + b = hc->busy[i]; + + if (!found) { + if (b != first) { + continue; + } + + dd("found first"); + found = 1; + } + + p = last; + + if (b == first) { + dd("request line: %.*s", (int) r->request_line.len, + r->request_line.data); + + if (no_req_line) { + last = ngx_copy(last, + r->request_line.data + r->request_line.len + + 2, + b->pos - r->request_line.data + - r->request_line.len - 2); + + } else { + last = ngx_copy(last, + r->request_line.data, + b->pos - r->request_line.data); + + } + + } else { + last = ngx_copy(last, b->start, b->pos - b->start); + } + +#if 1 + /* skip truncated header entries (if any) */ + while (last > p && last[-1] != LF) { + last--; + } +#endif + + for (; p != last; p++) { + if (*p == '\0') { + if (p + 1 == last) { + /* XXX this should not happen */ + dd("found string end!!"); + + } else if (*(p + 1) == LF) { + *p = CR; + + } else { + *p = ':'; + } + } + } + + if (b == r->header_in) { + break; + } + } + + } else { + if (no_req_line) { + last = ngx_copy(data, + r->request_line.data + r->request_line.len + 2, + size - r->request_line.len - 2); + + } else { + last = ngx_copy(data, r->request_line.data, size); + } + + for (p = data; p != last; p++) { + if (*p == '\0') { + if (p + 1 != last && *(p + 1) == LF) { + *p = CR; + + } else { + *p = ':'; + } + } + } + } + + lua_pushlstring(L, (char *) data, last - data); + return 1; +} + + static int ngx_http_lua_ngx_req_get_headers(lua_State *L) { ngx_list_part_t *part; @@ -506,6 +673,9 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version); lua_setfield(L, -2, "http_version"); + lua_pushcfunction(L, ngx_http_lua_ngx_req_raw_header); + lua_setfield(L, -2, "raw_header"); + lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear); lua_setfield(L, -2, "clear_header"); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index ce55b68314..2573860103 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2005,7 +2005,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* .req */ + lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */ ngx_http_lua_inject_req_header_api(log, L); ngx_http_lua_inject_req_uri_api(log, L); diff --git a/t/062-count.t b/t/062-count.t index 8b1bcd8893..544d909e25 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -124,7 +124,7 @@ n = 1 --- request GET /test --- response_body -n = 22 +n = 23 --- no_error_log [error] @@ -146,7 +146,7 @@ n = 22 --- request GET /test --- response_body -n = 22 +n = 23 --- no_error_log [error] @@ -173,7 +173,7 @@ n = 22 --- request GET /test --- response_body -n = 22 +n = 23 --- no_error_log [error] diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t new file mode 100644 index 0000000000..46ef2668b1 --- /dev/null +++ b/t/104-req-raw-header.t @@ -0,0 +1,359 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3 + 6); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: small header +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- request +GET /t +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +\r +} +--- no_error_log +[error] + + + +=== TEST 2: large header +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- request +GET /t +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 3: large header (no request line) +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } +--- request +GET /t +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 4: small header (no request line) +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } +--- request +GET /t +--- response_body eval +qq{Host: localhost\r +Connection: Close\r +\r +} +--- no_error_log +[error] + + + +=== TEST 5: small header (no request line, with leading CRLF) +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- response_body eval +qq{Host: localhost\r +Connection: close\r +\r +} +--- no_error_log +[error] + + + +=== TEST 6: small header, with leading CRLF +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +" +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +\r +} +--- no_error_log +[error] + + + +=== TEST 7: large header, with leading CRLF +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } + +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +". +(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 8: large header, with leading CRLF, excluding request line +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } + +--- raw_request eval +"\r\nGET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +". +(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- response_body eval +qq{Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 9: large header, with lots of leading CRLF, excluding request line +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } + +--- raw_request eval +("\r\n" x 534) . "GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +". +(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- response_body eval +qq{Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + + + +=== TEST 10: small header, pipelined +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- pipelined_requests eval +["GET /t", "GET /th"] + +--- more_headers +Foo: bar + +--- response_body eval +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +Foo: bar\r +\r +}, qq{GET /th HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar\r +\r +}] +--- no_error_log +[error] + + + +=== TEST 11: large header, pipelined +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- pipelined_requests eval +["GET /t", "GET /t"] + +--- more_headers eval +CORE::join "\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +my $headers = (CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"; + +[qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: keep-alive\r +$headers}, +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +$headers}] + +--- no_error_log +[error] + + + +=== TEST 12: small header, multi-line header +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar baz\r + blah +\r +" +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +Foo: bar baz\r + blah +\r +} +--- no_error_log +[error] + + + +=== TEST 13: large header, multi-line header +--- config + client_header_buffer_size 10; + large_client_header_buffers 50 567; + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } + +--- raw_request eval +my $headers = (CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n"; + +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +$headers} + +--- response_body eval +qq{GET /t HTTP/1.1\r +Host: localhost\r +Connection: close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n" + +--- no_error_log +[error] + From 53a46aaef95f4ccc74fcbefdfe7230fb0e2dca62 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 6 Mar 2013 17:17:52 -0800 Subject: [PATCH 0021/1981] docs: made it explicit that redirecting to external domains is also supported in ngx.redirect(). thanks Ron Gomes for asking. --- README | 4 ++++ README.markdown | 6 ++++++ doc/HttpLuaModule.wiki | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/README b/README index ae1329f78d..38f9e67ed6 100644 --- a/README +++ b/README @@ -2951,6 +2951,10 @@ Nginx API for Lua return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) + Redirecting arbitrary external URLs is also supported, for example: + + return ngx.redirect("http://www.google.com") + We can also use the numerical code directly as the second "status" argument: diff --git a/README.markdown b/README.markdown index cc3b4949f8..706c6c315c 100644 --- a/README.markdown +++ b/README.markdown @@ -2727,6 +2727,12 @@ which is equivalent to return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) +Redirecting arbitrary external URLs is also supported, for example: + + + return ngx.redirect("http://www.google.com") + + We can also use the numerical code directly as the second `status` argument: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 4e871b734c..59c5ac8e46 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2644,6 +2644,12 @@ which is equivalent to return ngx.redirect("http://localhost:1984/foo", ngx.HTTP_MOVED_TEMPORARILY) +Redirecting arbitrary external URLs is also supported, for example: + + + return ngx.redirect("http://www.google.com") + + We can also use the numerical code directly as the second status argument: From cf568da5966513bc5c4e81d42f4a958a9863a083 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 7 Mar 2013 15:41:38 -0800 Subject: [PATCH 0022/1981] fixed tests to reflect the typo fix in 4927e75b0507477f425a7296cf44119453363b2d. --- t/001-set.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/001-set.t b/t/001-set.t index 6b53f4cc65..b608b24654 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -157,7 +157,7 @@ GET /set-both --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -varaible "b" not found for writing; maybe it is a built-in variable that is not changeable or you forgot to use "set $b '';" in the config file to define it first +variable "b" not found for writing; maybe it is a built-in variable that is not changeable or you forgot to use "set $b '';" in the config file to define it first @@ -489,7 +489,7 @@ world --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -varaible "arg_foo" not found for writing; maybe it is a built-in variable that is not changeable or you forgot to use "set $arg_foo '';" in the config file to define it first +variable "arg_foo" not found for writing; maybe it is a built-in variable that is not changeable or you forgot to use "set $arg_foo '';" in the config file to define it first From 545b03fd5e60b9df661d1a6b6335b25082698027 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 7 Mar 2013 15:44:42 -0800 Subject: [PATCH 0023/1981] fixed tests to reflect output format changes in agentzh/echo-nginx-module@2adcf59ec5c3dff7592b9c04dd31d34cf2f778d5. --- t/028-req-header.t | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/t/028-req-header.t b/t/028-req-header.t index 4875b5aa7c..b02c19f089 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -647,7 +647,7 @@ Test-Header: [1] } location /back { - echo $echo_client_request_headers; + echo -n $echo_client_request_headers; } --- request POST /t @@ -658,6 +658,7 @@ Test-Header: 1 --- response_body_like eval qr/Connection: close\r Test-Header: 1\r +\r $/ --- no_error_log [error] @@ -801,7 +802,7 @@ My-Foo-Header: Hello World } location = /back { - echo $echo_client_request_headers; + echo -n $echo_client_request_headers; } --- request GET /t @@ -834,7 +835,7 @@ N: n\r O: o\r P: p\r Q: q\r - +\r " @@ -854,7 +855,7 @@ Q: q\r } location = /back { - echo $echo_client_request_headers; + echo -n $echo_client_request_headers; } --- request GET /t @@ -908,7 +909,7 @@ foo-18: 18\r foo-19: 19\r foo-20: 20\r foo-21: 21\r - +\r " @@ -926,7 +927,7 @@ foo-21: 21\r } location = /back { - echo $echo_client_request_headers; + echo -n $echo_client_request_headers; } --- request GET /t @@ -959,7 +960,7 @@ M: m\r N: n\r O: o\r P: p\r - +\r " @@ -980,7 +981,7 @@ P: p\r } location = /back { - echo $echo_client_request_headers; + echo -n $echo_client_request_headers; } --- request GET /t @@ -1034,7 +1035,7 @@ foo-18: 18\r foo-19: 19\r foo-20: 20\r foo-21: 21\r - +\r " From ba594765fa50691f039831e0b3030b71a5ec58d3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 7 Mar 2013 16:34:26 -0800 Subject: [PATCH 0024/1981] fixed ill-formed HTTP requests in a recently-added test case, which caused issues under the "check leaks" testing mode. --- t/104-req-raw-header.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index 46ef2668b1..0d19b0f7f5 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -313,7 +313,7 @@ $headers}] Host: localhost\r Connection: close\r Foo: bar baz\r - blah + blah\r \r " --- response_body eval @@ -321,7 +321,7 @@ qq{GET /t HTTP/1.1\r Host: localhost\r Connection: close\r Foo: bar baz\r - blah + blah\r \r } --- no_error_log From d86bb171305d9c550a5179db7c739c8eeb979d43 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 8 Mar 2013 18:10:52 -0800 Subject: [PATCH 0025/1981] bugfix: rewrite_by_lua_no_postpone can only work globally and did not reject contexts like "server" and "location" configuration blocks. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_module.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index b0a1fb469b..96dd35de96 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -187,8 +187,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_rewrite_handler_file }, { ngx_string("rewrite_by_lua_no_postpone"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(ngx_http_lua_main_conf_t, postponed_to_rewrite_phase_end), From 88b4fda412f0017dd4e0e8db293e65bb8e43765b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 10 Mar 2013 20:42:03 -0700 Subject: [PATCH 0026/1981] fixed the timeout settings for large header test cases in 104-req-raw-header.t. --- t/104-req-raw-header.t | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index 0d19b0f7f5..031947a79c 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -60,6 +60,7 @@ Connection: Close\r --- no_error_log [error] +--- timeout: 5 @@ -85,6 +86,7 @@ Connection: Close\r --- no_error_log [error] +--- timeout: 5 @@ -180,6 +182,7 @@ Connection: close\r --- no_error_log [error] +--- timeout: 5 @@ -208,6 +211,7 @@ Connection: close\r --- no_error_log [error] +--- timeout: 5 @@ -236,6 +240,7 @@ Connection: close\r --- no_error_log [error] +--- timeout: 5 @@ -298,6 +303,7 @@ $headers}] --- no_error_log [error] +--- timeout: 5 @@ -356,4 +362,5 @@ Connection: close\r --- no_error_log [error] +--- timeout: 5 From a768a65b25ebfb36a5d3e722db24f41fdc946018 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Mar 2013 12:23:08 -0700 Subject: [PATCH 0027/1981] updated docs to reflect recent changes; also bumped the version number to 0.7.17. --- README | 8 ++++---- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README b/README index 38f9e67ed6..b91af85f71 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.16 - () released on 22 - February 2013. + This document describes ngx_lua v0.7.17 + () released on 10 + March 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -1278,7 +1278,7 @@ Directives default: *rewrite_by_lua_no_postpone off* - context: *http, server, location, location-if* + context: *http* Controls whether or not to disable postponing rewrite_by_lua and rewrite_by_lua_file directives to run at the end of the "rewrite" diff --git a/README.markdown b/README.markdown index 706c6c315c..9c6cb15350 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.16](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 February 2013. +This document describes ngx_lua [v0.7.17](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 March 2013. Synopsis ======== @@ -1132,7 +1132,7 @@ rewrite_by_lua_no_postpone **default:** *rewrite_by_lua_no_postpone off* -**context:** *http, server, location, location-if* +**context:** *http* Controls whether or not to disable postponing [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) and [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) directives to run at the end of the `rewrite` request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the `rewrite` phase. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 59c5ac8e46..5976701883 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.16] released on 22 February 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.17] released on 10 March 2013. = Synopsis = @@ -1089,7 +1089,7 @@ This directive was first introduced in the v0.5.0rc19 release. '''default:''' ''rewrite_by_lua_no_postpone off'' -'''context:''' ''http, server, location, location-if'' +'''context:''' ''http'' Controls whether or not to disable postponing [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]] directives to run at the end of the rewrite request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the rewrite phase. From 04775502b2e348181282345320b727ab1a5a8808 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Mar 2013 18:35:42 -0700 Subject: [PATCH 0028/1981] bugfix: when the Lua code using TCP cosockets + resolver was run in a subrequest, the subrequest could hang due to missing calls to ngx_http_run_posted_requests in the TCP cosocket resolver handler. thanks Lanshun Zhou for reporting this issue in #215. --- src/ngx_http_lua_socket_tcp.c | 16 ++++++ t/058-tcp-socket.t | 98 ++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 12e8b759a0..676209ba62 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -639,6 +639,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->prepare_retvals = ngx_http_lua_socket_error_retval_handler; ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_RESOLVER); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -669,6 +674,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushnil(L); lua_pushliteral(L, "name cannot be resolved to a address"); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -690,6 +700,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushnil(L); lua_pushliteral(L, "out of memory"); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -719,6 +734,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) if (waiting) { lctx->resume_handler = ngx_http_lua_socket_tcp_resume; r->write_event_handler(r); + ngx_http_run_posted_requests(r->connection); } else { (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L); diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index fd530b5c06..d12567062c 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -3,9 +3,9 @@ use lib 'lib'; use Test::Nginx::Socket; -#repeat_each(2); +repeat_each(2); -plan tests => repeat_each() * 87; +plan tests => repeat_each() * 94; our $HtmlDir = html_dir; @@ -1988,3 +1988,97 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 33: 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.tcp() + local ok, err = sock:connect("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 /lua +--- response_body_like chop +^failed to connect to xxx: xxx could not be resolved.*?Host not found + +--- no_error_log +[error] + + + +=== TEST 34: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) +--- config + resolver 8.8.8.8; + + 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.tcp() + local ok, err = sock:connect(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! + +--- stap +F(ngx_http_lua_socket_resolve_handler) { + println("lua socket resolve handler") +} + +F(ngx_http_lua_socket_tcp_connect_retval_handler) { + println("lua socket tcp connect retval handler") +} + +F(ngx_http_run_posted_requests) { + println("run posted requests") +} + +--- stap_out_like +run posted requests +lua socket resolve handler +run posted requests +lua socket tcp connect retval handler +run posted requests + +--- no_error_log +[error] + From f84ca22c30091c75955d44bd790a714b1ef0bbe9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 15 Mar 2013 23:39:32 -0700 Subject: [PATCH 0029/1981] bugfix: when the Lua code using UDP cosockets + resolver was run in a subrequest, the subrequest could hang due to missing calls to ngx_http_run_posted_requests in the UDP cosocket resolver handler. thanks Lanshun Zhou for reporting this issue in #215. --- src/ngx_http_lua_socket_udp.c | 16 ++++++++ t/087-udp-socket.t | 74 +++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index fd386634da..fcc1fe47c4 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -456,6 +456,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->prepare_retvals = ngx_http_lua_socket_error_retval_handler; ngx_http_lua_socket_udp_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_RESOLVER); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -486,6 +491,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushnil(L); lua_pushliteral(L, "name cannot be resolved to a address"); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -507,6 +517,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushnil(L); lua_pushliteral(L, "out of memory"); + + if (waiting) { + ngx_http_run_posted_requests(r->connection); + } + return; } @@ -536,6 +551,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) if (waiting) { lctx->resume_handler = ngx_http_lua_socket_udp_resume; r->write_event_handler(r); + ngx_http_run_posted_requests(r->connection); } else { (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 87933c6cc8..04b74a8bc2 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -652,3 +652,77 @@ received a good response. --- 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 /lua +--- 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; + + 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] + From 5c4c4e429c7c5af9e7ac0db7a9bcc076f10aa007 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 16 Mar 2013 21:34:28 -0700 Subject: [PATCH 0030/1981] tests: avoided using taobao.com in the test suite; also decreased the resolver_timeout setting. --- t/023-rewrite/tcp-socket.t | 8 ++++---- t/058-tcp-socket.t | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 5b1a9f8501..8ba8ae6eeb 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -206,7 +206,7 @@ attempt to send data on a closed socket: --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; - resolver_timeout 5s; + resolver_timeout 1s; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -301,11 +301,11 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; - resolver_timeout 2s; + resolver_timeout 1s; location /test { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("taobao.com", 16787) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes @@ -373,7 +373,7 @@ connected: 1 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; - resolver_timeout 4s; + resolver_timeout 1s; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index d12567062c..d3911fb7b5 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -202,7 +202,7 @@ attempt to send data on a closed socket: --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; - resolver_timeout 5s; + resolver_timeout 1s; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -294,7 +294,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; - resolver_timeout 2s; + resolver_timeout 1s; location /test { content_by_lua ' local sock = ngx.socket.tcp() @@ -362,7 +362,7 @@ connected: 1 --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; - resolver_timeout 4s; + resolver_timeout 1s; location /t { content_by_lua ' local sock = ngx.socket.tcp() From a62eadd492759bbbc030b1172c3ddeaaed02d0b7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 17 Mar 2013 13:18:14 -0700 Subject: [PATCH 0031/1981] bugfix: invalid memory access might happen when the TCP cosockets were used. this regression had appeared in the commit 04775502b2e348181282345320b727ab1a5a8808. --- src/ngx_http_lua_socket_tcp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 676209ba62..212b497aff 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -594,6 +594,7 @@ static void ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) { ngx_http_request_t *r; + ngx_connection_t *c; ngx_http_upstream_resolved_t *ur; ngx_http_lua_ctx_t *lctx; lua_State *L; @@ -606,9 +607,10 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u = ctx->data; r = u->request; + c = r->connection; ur = u->resolved; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua tcp socket resolve handler"); lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -625,7 +627,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) waiting = u->waiting; if (ctx->state) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua tcp socket resolver error: %s (waiting: %d)", ngx_resolver_strerror(ctx->state), (int) u->waiting); @@ -641,7 +643,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) NGX_HTTP_LUA_SOCKET_FT_RESOLVER); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -660,7 +662,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) addr = ntohl(ctx->addrs[i]); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, "name was resolved to %ud.%ud.%ud.%ud", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); @@ -676,7 +678,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushliteral(L, "name cannot be resolved to a address"); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -702,7 +704,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushliteral(L, "out of memory"); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -734,7 +736,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) if (waiting) { lctx->resume_handler = ngx_http_lua_socket_tcp_resume; r->write_event_handler(r); - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } else { (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L); From 835aea95fae66cc83557180a19a220cb641ecf8b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 17 Mar 2013 13:33:36 -0700 Subject: [PATCH 0032/1981] bugfix: invalid memory access might happen when the UDP cosockets were used. this regression had appeared in the commit f84ca22c30091c75955d44bd790a714b1ef0bbe9. --- src/ngx_http_lua_socket_udp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index fcc1fe47c4..5d787c77d6 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -409,6 +409,7 @@ static void ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) { ngx_http_request_t *r; + ngx_connection_t *c; ngx_http_upstream_resolved_t *ur; ngx_http_lua_ctx_t *lctx; lua_State *L; @@ -421,9 +422,10 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u = ctx->data; r = u->request; + c = r->connection; ur = u->resolved; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua udp socket resolve handler"); lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -442,7 +444,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) waiting = u->waiting; if (ctx->state) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua udp socket resolver error: %s (waiting: %d)", ngx_resolver_strerror(ctx->state), (int) u->waiting); @@ -458,7 +460,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) NGX_HTTP_LUA_SOCKET_FT_RESOLVER); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -477,7 +479,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) addr = ntohl(ctx->addrs[i]); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, "name was resolved to %ud.%ud.%ud.%ud", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); @@ -493,7 +495,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushliteral(L, "name cannot be resolved to a address"); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -519,7 +521,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_pushliteral(L, "out of memory"); if (waiting) { - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } return; @@ -551,7 +553,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) if (waiting) { lctx->resume_handler = ngx_http_lua_socket_udp_resume; r->write_event_handler(r); - ngx_http_run_posted_requests(r->connection); + ngx_http_run_posted_requests(c); } else { (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L); From 17b349e97206c3d0a43cc3a77bd91af20682d030 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 17 Mar 2013 17:16:18 -0700 Subject: [PATCH 0033/1981] feature: added new methods safe_set and safe_get to ngx.shared.DICT objects, which never override existing unexpired items but immediately return nil and a "no memory" string message when running out of storage. thanks Matthieu Tourne for requesting this. --- README | 38 ++++++++++++++++++ README.markdown | 26 +++++++++++++ doc/HttpLuaModule.wiki | 24 ++++++++++++ src/ngx_http_lua_shdict.c | 32 ++++++++++++++++ t/043-shdict.t | 81 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 200 insertions(+), 1 deletion(-) diff --git a/README b/README index b91af85f71..8fb5142121 100644 --- a/README +++ b/README @@ -3832,8 +3832,12 @@ Nginx API for Lua * set + * safe_set + * add + * safe_add + * replace * incr @@ -3994,6 +3998,23 @@ Nginx API for Lua See also ngx.shared.DICT. + ngx.shared.DICT.safe_set + syntax: *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, + flags?)* + + context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, + content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, + log_by_lua** + + Similar to the set method, but never overrides the (least recently used) + unexpired items in the store when running out of storage in the shared + memory zone. In this case, it will immediately return "nil" and the + string "no memory". + + This feature was first introduced in the "v0.7.18" release. + + See also ngx.shared.DICT. + ngx.shared.DICT.add syntax: *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* @@ -4013,6 +4034,23 @@ Nginx API for Lua See also ngx.shared.DICT. + ngx.shared.DICT.safe_add + syntax: *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, + flags?)* + + context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, + content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, + log_by_lua** + + Similar to the add method, but never overrides the (least recently used) + unexpired items in the store when running out of storage in the shared + memory zone. In this case, it will immediately return "nil" and the + string "no memory". + + This feature was first introduced in the "v0.7.18" release. + + See also ngx.shared.DICT. + ngx.shared.DICT.replace syntax: *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* diff --git a/README.markdown b/README.markdown index 9c6cb15350..fd06f0d40f 100644 --- a/README.markdown +++ b/README.markdown @@ -3553,7 +3553,9 @@ The resulting object `dict` has the following methods: * [get](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.get) * [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) +* [safe_set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.safe_set) * [add](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.add) +* [safe_add](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.safe_add) * [replace](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.replace) * [incr](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.incr) * [delete](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.delete) @@ -3680,6 +3682,18 @@ Please note that while internally the key-value pair is set atomically, the atom See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). +ngx.shared.DICT.safe_set +------------------------ +**syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + +Similar to the [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". + +This feature was first introduced in the `v0.7.18` release. + +See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). + ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* @@ -3694,6 +3708,18 @@ This feature was first introduced in the `v0.3.1rc22` release. See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). +ngx.shared.DICT.safe_add +------------------------ +**syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + +Similar to the [add](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.add) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". + +This feature was first introduced in the `v0.7.18` release. + +See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). + ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5976701883..6cf97b8a6b 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3433,7 +3433,9 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.get|get]] * [[#ngx.shared.DICT.set|set]] +* [[#ngx.shared.DICT.safe_set|safe_set]] * [[#ngx.shared.DICT.add|add]] +* [[#ngx.shared.DICT.safe_add|safe_add]] * [[#ngx.shared.DICT.replace|replace]] * [[#ngx.shared.DICT.incr|incr]] * [[#ngx.shared.DICT.delete|delete]] @@ -3558,6 +3560,17 @@ Please note that while internally the key-value pair is set atomically, the atom See also [[#ngx.shared.DICT|ngx.shared.DICT]]. +== ngx.shared.DICT.safe_set == +'''syntax:''' ''ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' + +Similar to the [[#ngx.shared.DICT.set|set]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". + +This feature was first introduced in the v0.7.18 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.add == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)'' @@ -3571,6 +3584,17 @@ This feature was first introduced in the v0.3.1rc22 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. +== ngx.shared.DICT.safe_add == +'''syntax:''' ''ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' + +Similar to the [[#ngx.shared.DICT.add|add]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". + +This feature was first introduced in the v0.7.18 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.replace == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)'' diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 28d83a580a..b5cec33374 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -16,6 +16,7 @@ static int ngx_http_lua_shdict_set(lua_State *L); +static int ngx_http_lua_shdict_safe_set(lua_State *L); static int ngx_http_lua_shdict_get(lua_State *L); static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n); @@ -24,6 +25,7 @@ static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_http_lua_shdict_node_t **sdp); static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags); static int ngx_http_lua_shdict_add(lua_State *L); +static int ngx_http_lua_shdict_safe_add(lua_State *L); static int ngx_http_lua_shdict_replace(lua_State *L); static int ngx_http_lua_shdict_incr(lua_State *L); static int ngx_http_lua_shdict_delete(lua_State *L); @@ -34,6 +36,7 @@ static int ngx_http_lua_shdict_get_keys(lua_State *L); #define NGX_HTTP_LUA_SHDICT_ADD 0x0001 #define NGX_HTTP_LUA_SHDICT_REPLACE 0x0002 +#define NGX_HTTP_LUA_SHDICT_SAFE_STORE 0x0004 ngx_int_t @@ -296,9 +299,15 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_pushcfunction(L, ngx_http_lua_shdict_set); lua_setfield(L, -2, "set"); + lua_pushcfunction(L, ngx_http_lua_shdict_safe_set); + lua_setfield(L, -2, "safe_set"); + lua_pushcfunction(L, ngx_http_lua_shdict_add); lua_setfield(L, -2, "add"); + lua_pushcfunction(L, ngx_http_lua_shdict_safe_add); + lua_setfield(L, -2, "safe_add"); + lua_pushcfunction(L, ngx_http_lua_shdict_replace); lua_setfield(L, -2, "replace"); @@ -727,6 +736,14 @@ ngx_http_lua_shdict_add(lua_State *L) } +static int +ngx_http_lua_shdict_safe_add(lua_State *L) +{ + return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_ADD + |NGX_HTTP_LUA_SHDICT_SAFE_STORE); +} + + static int ngx_http_lua_shdict_replace(lua_State *L) { @@ -741,6 +758,13 @@ ngx_http_lua_shdict_set(lua_State *L) } +static int +ngx_http_lua_shdict_safe_set(lua_State *L) +{ + return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_SAFE_STORE); +} + + static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags) { @@ -979,6 +1003,14 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (node == NULL) { + if (flags & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + return 2; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%V\"", &name); diff --git a/t/043-shdict.t b/t/043-shdict.t index be87c69e57..814fffad16 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 15); #no_diff(); no_long_string(); @@ -1373,3 +1373,82 @@ GET /t --- response_body 2048 + + +=== TEST 58: safe_set +--- http_config + lua_shared_dict dogs 100k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + local i = 0 + while i < 1000 do + i = i + 1 + local val = string.rep(" hello", 10) .. i + local res, err = dogs:safe_set("key_" .. i, val) + if not res then + ngx.say(res, " ", err) + break + end + end + ngx.say("abort at ", i) + ngx.say("cur value: ", dogs:get("key_" .. i)) + if i > 1 then + ngx.say("1st value: ", dogs:get("key_1")) + end + if i > 2 then + ngx.say("2nd value: ", dogs:get("key_2")) + end + '; + } +--- pipelined_requests eval +["GET /test", "GET /test"] +--- response_body eval +my $a = "nil no memory\nabort at (353|705)\ncur value: nil\n1st value: " . (" hello" x 10) . "1\n2nd value: " . (" hello" x 10) . "2\n"; +[qr/$a/, qr/$a/] +--- no_error_log +[error] + + + +=== TEST 59: safe_add +--- http_config + lua_shared_dict dogs 100k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + local i = 0 + while i < 1000 do + i = i + 1 + local val = string.rep(" hello", 10) .. i + local res, err = dogs:safe_add("key_" .. i, val) + if not res then + ngx.say(res, " ", err) + break + end + end + ngx.say("abort at ", i) + ngx.say("cur value: ", dogs:get("key_" .. i)) + if i > 1 then + ngx.say("1st value: ", dogs:get("key_1")) + end + if i > 2 then + ngx.say("2nd value: ", dogs:get("key_2")) + end + '; + } +--- pipelined_requests eval +["GET /test", "GET /test"] +--- response_body eval +my $a = "nil no memory\nabort at (353|705)\ncur value: nil\n1st value: " . (" hello" x 10) . "1\n2nd value: " . (" hello" x 10) . "2\n"; +[qr/$a/, +q{false exists +abort at 1 +cur value: hello hello hello hello hello hello hello hello hello hello1 +} +] +--- no_error_log +[error] + From 3ea32c96932ebb63d234cd7b4165d63b350af323 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 17 Mar 2013 20:16:05 -0700 Subject: [PATCH 0034/1981] api-change: the ngx.re.match, ngx.re.gmatch, ngx.re.sub, and ngx.re.gsub functions used to throw Lua exceptions aggressively for all the error conditions; now they return an additonal string describing the error for almost all common errors instead of throwing exceptions, including pcre compile-time and exec-time failures. thanks Matthieu Tourne for requesting this change. --- README | 117 ++++++++++++++++++++++++------- README.markdown | 109 +++++++++++++++++++++------- doc/HttpLuaModule.wiki | 109 +++++++++++++++++++++------- src/ngx_http_lua_regex.c | 59 +++++++++++----- t/034-match.t | 71 +++++++++++++++---- t/035-gmatch.t | 62 +++++++++++++++- t/036-sub.t | 148 +++++++++++++++++++++++++++------------ t/037-gsub.t | 29 +++++++- t/038-match-o.t | 20 +++--- t/039-sub-o.t | 109 ++++++++++++++++------------ t/047-match-jit.t | 20 +++--- t/049-gmatch-jit.t | 10 +-- t/050-gmatch-dfa.t | 10 +-- t/051-sub-jit.t | 22 +++--- t/052-sub-dfa.t | 28 ++++++-- t/053-gsub-jit.t | 22 +++--- t/054-gsub-dfa.t | 25 +++++-- 17 files changed, 716 insertions(+), 254 deletions(-) diff --git a/README b/README index b91af85f71..4f2abc4696 100644 --- a/README +++ b/README @@ -3550,7 +3550,7 @@ Nginx API for Lua otherwise. ngx.re.match - syntax: *captures = ngx.re.match(subject, regex, options?, ctx?)* + syntax: *captures, err = ngx.re.match(subject, regex, options?, ctx?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** @@ -3559,18 +3559,29 @@ Nginx API for Lua expression "regex" with the optional "options". Only the first occurrence of the match is returned, or "nil" if no match - is found. In case of fatal errors, like seeing bad "UTF-8" sequences in - "UTF-8" mode, a Lua exception will be raised. + is found. In case of errors, like seeing a bad regular expression or + exceeding the PCRE stack limit, `nil` and a string describing the error + will be returned. When a match is found, a Lua table "captures" is returned, where "captures[0]" holds the whole substring being matched, and "captures[1]" holds the first parenthesized sub-pattern's capturing, "captures[2]" the second, and so on. - local m = ngx.re.match("hello, 1234", "[0-9]+") - -- m[0] == "1234" + local m, err = ngx.re.match("hello, 1234", "[0-9]+") + if m then + -- m[0] == "1234" + + else + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + ngx.say("match not found") + end - local m = ngx.re.match("hello, 1234", "([0-9])[0-9]+") + local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") -- m[0] == "1234" -- m[1] == "1" @@ -3578,7 +3589,7 @@ Nginx API for Lua returned in the same Lua table as key-value pairs as the numbered captures. - local m = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") -- m[0] == "1234" -- m[1] == "1" -- m[2] == "234" @@ -3587,7 +3598,7 @@ Nginx API for Lua Unmatched subpatterns will have "nil" values in their "captures" table fields. - local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" @@ -3660,12 +3671,12 @@ Nginx API for Lua match. When match fails, the "ctx" table will be left intact. local ctx = {} - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "1234" -- ctx.pos == 4 local ctx = { pos = 2 } - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "34" -- ctx.pos == 4 @@ -3690,7 +3701,7 @@ Nginx API for Lua This feature was introduced in the "v0.2.1rc11" release. ngx.re.gmatch - syntax: *iterator = ngx.re.gmatch(subject, regex, options?)* + syntax: *iterator, err = ngx.re.gmatch(subject, regex, options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** @@ -3699,17 +3710,57 @@ Nginx API for Lua let the user programmer iterate all the matches over the "" string argument with the PCRE "regex". + In case of errors, like seeing an ill-formed regular expression, `nil` + and a string describing the error will be returned. + Here is a small example to demonstrate its basic usage: - local iterator = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not iterator then + ngx.log(ngx.ERR, "error: ", err) + return + end + local m - m = iterator() -- m[0] == m[1] == "hello" - m = iterator() -- m[0] == m[1] == "world" - m = iterator() -- m == nil + m, err = iterator() -- m[0] == m[1] == "hello" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m[0] == m[1] == "world" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m == nil + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + More often we just put it into a Lua loop: + + local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not it then + ngx.log(ngx.ERR, "error: ", err) + return + end + + while true do + local m, err = it() + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end - More often we just put it into a Lua "for" loop: + if not m then + -- no match found (any more) + break + end - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do + -- found a match ngx.say(m[0]) ngx.say(m[1]) end @@ -3727,7 +3778,7 @@ Nginx API for Lua This feature was first introduced in the "v0.2.1rc12" release. ngx.re.sub - syntax: *newstr, n = ngx.re.sub(subject, regex, replace, options?)* + syntax: *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** @@ -3738,31 +3789,37 @@ Nginx API for Lua meaning as in ngx.re.match. This method returns the resulting new string as well as the number of - successful substitutions, or throw out a Lua exception when an error - occurred (syntax errors in the "" string argument, for - example). + successful substitutions. In case of failures, like syntax errors in the + regular expressions or the "" string argument, it will return + `nil` and a string describing the error. When the "replace" is a string, then it is treated as a special template for string replacement. For example, - local newstr, n = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + if newstr then -- newstr == "hello, [12][1]34" -- n == 1 + else + ngx.log(ngx.ERR, "error: ", err) + return + end + where $0 referring to the whole substring matched by the pattern and $1 referring to the first parenthesized capturing substring. Curly braces can also be used to disambiguate variable names from the background string literals: - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") -- newstr == "hello, 10034" -- n == 1 Literal dollar sign characters ("$") in the "replace" string argument can be escaped by another dollar sign, for instance, - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "$$") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") -- newstr == "hello, $234" -- n == 1 @@ -3778,7 +3835,7 @@ Nginx API for Lua local func = function (m) return "[" .. m[0] .. "][" .. m[1] .. "]" end - local newstr, n = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") + local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") -- newstr == "hello, [12][1]34" -- n == 1 @@ -3800,14 +3857,20 @@ Nginx API for Lua Here is some examples: - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 + else + ngx.log(ngx.ERR, "error: ", err) + return + end + local func = function (m) return "[" .. m[0] .. "," .. m[1] .. "]" end - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") -- newstr == "[hello,h], [world,w]" -- n == 2 diff --git a/README.markdown b/README.markdown index 9c6cb15350..828ac88804 100644 --- a/README.markdown +++ b/README.markdown @@ -3291,23 +3291,33 @@ Returns `true` if the current request is an nginx subrequest, or `false` otherwi ngx.re.match ------------ -**syntax:** *captures = ngx.re.match(subject, regex, options?, ctx?)* +**syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. -Only the first occurrence of the match is returned, or `nil` if no match is found. In case of fatal errors, like seeing bad `UTF-8` sequences in `UTF-8` mode, a Lua exception will be raised. +Only the first occurrence of the match is returned, or `nil` if no match is found. In case of errors, like seeing a bad regular expression or exceeding the PCRE stack limit, `nil` and a string describing the error will be returned. When a match is found, a Lua table `captures` is returned, where `captures[0]` holds the whole substring being matched, and `captures[1]` holds the first parenthesized sub-pattern's capturing, `captures[2]` the second, and so on. - local m = ngx.re.match("hello, 1234", "[0-9]+") - -- m[0] == "1234" + local m, err = ngx.re.match("hello, 1234", "[0-9]+") + if m then + -- m[0] == "1234" + + else + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + ngx.say("match not found") + end - local m = ngx.re.match("hello, 1234", "([0-9])[0-9]+") + local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") -- m[0] == "1234" -- m[1] == "1" @@ -3316,7 +3326,7 @@ Named captures are also supported since the `v0.7.14` release and are returned in the same Lua table as key-value pairs as the numbered captures. - local m = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") -- m[0] == "1234" -- m[1] == "1" -- m[2] == "234" @@ -3326,7 +3336,7 @@ and are returned in the same Lua table as key-value pairs as the numbered captur Unmatched subpatterns will have `nil` values in their `captures` table fields. - local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" @@ -3396,14 +3406,14 @@ The optional fourth argument, `ctx`, can be a Lua table holding an optional `pos local ctx = {} - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "1234" -- ctx.pos == 4 local ctx = { pos = 2 } - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "34" -- ctx.pos == 4 @@ -3424,26 +3434,65 @@ This feature was introduced in the `v0.2.1rc11` release. ngx.re.gmatch ------------- -**syntax:** *iterator = ngx.re.gmatch(subject, regex, options?)* +**syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Similar to [ngx.re.match](http://wiki.nginx.org/HttpLuaModule#ngx.re.match), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. +In case of errors, like seeing an ill-formed regular expression, `nil` and a string describing the error will be returned. + Here is a small example to demonstrate its basic usage: - local iterator = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not iterator then + ngx.log(ngx.ERR, "error: ", err) + return + end + local m - m = iterator() -- m[0] == m[1] == "hello" - m = iterator() -- m[0] == m[1] == "world" - m = iterator() -- m == nil + m, err = iterator() -- m[0] == m[1] == "hello" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m[0] == m[1] == "world" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m == nil + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + +More often we just put it into a Lua loop: + + local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not it then + ngx.log(ngx.ERR, "error: ", err) + return + end -More often we just put it into a Lua `for` loop: + while true do + local m, err = it() + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + if not m then + -- no match found (any more) + break + end - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do + -- found a match ngx.say(m[0]) ngx.say(m[1]) end @@ -3459,28 +3508,34 @@ This feature was first introduced in the `v0.2.1rc12` release. ngx.re.sub ---------- -**syntax:** *newstr, n = ngx.re.sub(subject, regex, replace, options?)* +**syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](http://wiki.nginx.org/HttpLuaModule#ngx.re.match). -This method returns the resulting new string as well as the number of successful substitutions, or throw out a Lua exception when an error occurred (syntax errors in the `` string argument, for example). +This method returns the resulting new string as well as the number of successful substitutions. In case of failures, like syntax errors in the regular expressions or the `` string argument, it will return `nil` and a string describing the error. When the `replace` is a string, then it is treated as a special template for string replacement. For example, - local newstr, n = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + if newstr then -- newstr == "hello, [12][1]34" -- n == 1 + else + ngx.log(ngx.ERR, "error: ", err) + return + end + where `$0` referring to the whole substring matched by the pattern and `$1` referring to the first parenthesized capturing substring. Curly braces can also be used to disambiguate variable names from the background string literals: - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") -- newstr == "hello, 10034" -- n == 1 @@ -3488,7 +3543,7 @@ Curly braces can also be used to disambiguate variable names from the background Literal dollar sign characters (`$`) in the `replace` string argument can be escaped by another dollar sign, for instance, - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "$$") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") -- newstr == "hello, $234" -- n == 1 @@ -3501,7 +3556,7 @@ When the `replace` argument is of type "function", then it will be invoked with local func = function (m) return "[" .. m[0] .. "][" .. m[1] .. "]" end - local newstr, n = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") + local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") -- newstr == "hello, [12][1]34" -- n == 1 @@ -3523,16 +3578,22 @@ Just like [ngx.re.sub](http://wiki.nginx.org/HttpLuaModule#ngx.re.sub), but does Here is some examples: - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 + else + ngx.log(ngx.ERR, "error: ", err) + return + end + local func = function (m) return "[" .. m[0] .. "," .. m[1] .. "]" end - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") -- newstr == "[hello,h], [world,w]" -- n == 2 diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5976701883..ee8767461d 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3175,23 +3175,33 @@ Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) int Returns true if the current request is an nginx subrequest, or false otherwise. == ngx.re.match == -'''syntax:''' ''captures = ngx.re.match(subject, regex, options?, ctx?)'' +'''syntax:''' ''captures, err = ngx.re.match(subject, regex, options?, ctx?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' Matches the subject string using the Perl compatible regular expression regex with the optional options. -Only the first occurrence of the match is returned, or nil if no match is found. In case of fatal errors, like seeing bad UTF-8 sequences in UTF-8 mode, a Lua exception will be raised. +Only the first occurrence of the match is returned, or nil if no match is found. In case of errors, like seeing a bad regular expression or exceeding the PCRE stack limit, `nil` and a string describing the error will be returned. When a match is found, a Lua table captures is returned, where captures[0] holds the whole substring being matched, and captures[1] holds the first parenthesized sub-pattern's capturing, captures[2] the second, and so on. - local m = ngx.re.match("hello, 1234", "[0-9]+") - -- m[0] == "1234" + local m, err = ngx.re.match("hello, 1234", "[0-9]+") + if m then + -- m[0] == "1234" + + else + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + ngx.say("match not found") + end - local m = ngx.re.match("hello, 1234", "([0-9])[0-9]+") + local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+") -- m[0] == "1234" -- m[1] == "1" @@ -3200,7 +3210,7 @@ Named captures are also supported since the v0.7.14 release and are returned in the same Lua table as key-value pairs as the numbered captures. - local m = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + local m, err = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") -- m[0] == "1234" -- m[1] == "1" -- m[2] == "234" @@ -3210,7 +3220,7 @@ and are returned in the same Lua table as key-value pairs as the numbered captur Unmatched subpatterns will have nil values in their captures table fields. - local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" @@ -3280,14 +3290,14 @@ The optional fourth argument, ctx, can be a Lua table holding an op local ctx = {} - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "1234" -- ctx.pos == 4 local ctx = { pos = 2 } - local m = ngx.re.match("1234, hello", "[0-9]+", "", ctx) + local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) -- m[0] = "34" -- ctx.pos == 4 @@ -3307,26 +3317,65 @@ To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the This feature was introduced in the v0.2.1rc11 release. == ngx.re.gmatch == -'''syntax:''' ''iterator = ngx.re.gmatch(subject, regex, options?)'' +'''syntax:''' ''iterator, err = ngx.re.gmatch(subject, regex, options?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. +In case of errors, like seeing an ill-formed regular expression, `nil` and a string describing the error will be returned. + Here is a small example to demonstrate its basic usage: - local iterator = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not iterator then + ngx.log(ngx.ERR, "error: ", err) + return + end + local m - m = iterator() -- m[0] == m[1] == "hello" - m = iterator() -- m[0] == m[1] == "world" - m = iterator() -- m == nil + m, err = iterator() -- m[0] == m[1] == "hello" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m[0] == m[1] == "world" + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + m, err = iterator() -- m == nil + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end -More often we just put it into a Lua for loop: +More often we just put it into a Lua loop: - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do + local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + if not it then + ngx.log(ngx.ERR, "error: ", err) + return + end + + while true do + local m, err = it() + if err then + ngx.log(ngx.ERR, "error: ", err) + return + end + + if not m then + -- no match found (any more) + break + end + + -- found a match ngx.say(m[0]) ngx.say(m[1]) end @@ -3341,20 +3390,26 @@ This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequen This feature was first introduced in the v0.2.1rc12 release. == ngx.re.sub == -'''syntax:''' ''newstr, n = ngx.re.sub(subject, regex, replace, options?)'' +'''syntax:''' ''newstr, n, err = ngx.re.sub(subject, regex, replace, options?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. -This method returns the resulting new string as well as the number of successful substitutions, or throw out a Lua exception when an error occurred (syntax errors in the string argument, for example). +This method returns the resulting new string as well as the number of successful substitutions. In case of failures, like syntax errors in the regular expressions or the string argument, it will return `nil` and a string describing the error. When the replace is a string, then it is treated as a special template for string replacement. For example, - local newstr, n = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]") + if newstr then -- newstr == "hello, [12][1]34" -- n == 1 + + else + ngx.log(ngx.ERR, "error: ", err) + return + end where $0 referring to the whole substring matched by the pattern and $1 referring to the first parenthesized capturing substring. @@ -3362,7 +3417,7 @@ where $0 referring to the whole substring matched by the pattern an Curly braces can also be used to disambiguate variable names from the background string literals: - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") -- newstr == "hello, 10034" -- n == 1 @@ -3370,7 +3425,7 @@ Curly braces can also be used to disambiguate variable names from the background Literal dollar sign characters ($) in the replace string argument can be escaped by another dollar sign, for instance, - local newstr, n = ngx.re.sub("hello, 1234", "[0-9]", "$$") + local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$") -- newstr == "hello, $234" -- n == 1 @@ -3383,7 +3438,7 @@ When the replace argument is of type "function", then it will be in local func = function (m) return "[" .. m[0] .. "][" .. m[1] .. "]" end - local newstr, n = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") + local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x") -- newstr == "hello, [12][1]34" -- n == 1 @@ -3404,16 +3459,22 @@ Just like [[#ngx.re.sub|ngx.re.sub]], but does global substitution. Here is some examples: - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i") + if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 + + else + ngx.log(ngx.ERR, "error: ", err) + return + end local func = function (m) return "[" .. m[0] .. "," .. m[1] .. "]" end - local newstr, n = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") + local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i") -- newstr == "[hello,h], [world,w]" -- n == 2 diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 2f9bd2aadc..41d0701ba1 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -284,11 +284,13 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (rc != NGX_OK) { dd("compile failed"); + lua_pushnil(L); + re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); - return luaL_argerror(L, 2, msg); + return 2; } #if (LUA_HAVE_PCRE_JIT) @@ -367,7 +369,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "out of memory"; + msg = "no memory"; goto error; } @@ -380,7 +382,8 @@ ngx_http_lua_ngx_re_match(lua_State *L) re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { - return luaL_error(L, "out of memory"); + msg = "no memory"; + goto error; } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, @@ -537,7 +540,9 @@ ngx_http_lua_ngx_re_match(lua_State *L) } } - return luaL_error(L, msg); + lua_pushnil(L); + lua_pushstring(L, msg); + return 2; } @@ -694,11 +699,13 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (rc != NGX_OK) { dd("compile failed"); + lua_pushnil(L); + re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); - return luaL_argerror(L, 2, msg); + return 2; } #if LUA_HAVE_PCRE_JIT @@ -775,7 +782,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "out of memory"; + msg = "no memory"; goto error; } @@ -788,7 +795,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { - return luaL_error(L, "out of memory"); + msg = "no memory"; + goto error; } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, @@ -830,7 +838,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - return luaL_error(L, "out of memory"); + msg = "no memory"; + goto error; } cln->handler = ngx_http_lua_ngx_re_gmatch_cleanup; @@ -863,7 +872,9 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) } } - return luaL_error(L, msg); + lua_pushnil(L); + lua_pushstring(L, msg); + return 2; } @@ -1051,7 +1062,9 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) ngx_pfree(r->pool, cap); } - return luaL_error(L, msg); + lua_pushnil(L); + lua_pushstring(L, msg); + return 2; } @@ -1356,11 +1369,14 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (rc != NGX_OK) { dd("compile failed"); + lua_pushnil(L); + lua_pushnil(L); + re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); - return luaL_argerror(L, 2, msg); + return 3; } #if LUA_HAVE_PCRE_JIT @@ -1437,7 +1453,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "out of memory"; + msg = "no memory"; goto error; } @@ -1448,7 +1464,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ctpl = ngx_palloc(pool, sizeof(ngx_http_lua_complex_value_t)); if (ctpl == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "out of memory"; + msg = "no memory"; goto error; } @@ -1457,7 +1473,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) p = ngx_palloc(pool, tpl.len + 1); if (p == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "out of memory"; + msg = "no memory"; goto error; } @@ -1487,8 +1503,11 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ngx_pfree(pool, re_comp.regex); - return luaL_error(L, "bad template for substitution: \"%s\"", - lua_tostring(L, 3)); + lua_pushnil(L); + lua_pushnil(L); + lua_pushfstring(L, "bad template for substitution: \"%s\"", + lua_tostring(L, 3)); + return 3; } } @@ -1501,7 +1520,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { - return luaL_error(L, "out of memory"); + msg = "no memory"; + goto error; } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, @@ -1755,7 +1775,10 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } } - return luaL_error(L, msg); + lua_pushnil(L); + lua_pushnil(L); + lua_pushstring(L, msg); + return 3; } diff --git a/t/034-match.t b/t/034-match.t index 65d5bd8142..6efefe787d 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 10); #no_diff(); no_long_string(); @@ -345,22 +345,26 @@ he --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", "(abc") - if rc then - if m then - ngx.say(m[0]) + local m, err = ngx.re.match("hello\\nworld", "(abc") + if m then + ngx.say(m[0]) + + else + if err then + ngx.say("error: ", err) + else ngx.say("not matched: ", m) end - else - ngx.say("error: ", m) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] @@ -628,20 +632,27 @@ regex: (?:>[\w\s]*) --- config location /re { content_by_lua ' - m = ngx.re.match("hello, 1234", "([0-9]+") + local m, err = ngx.re.match("hello, 1234", "([0-9]+") if m then ngx.say(m[0]) + else - ngx.say("not matched!") + if err then + ngx.say("error: ", err) + + else + ngx.say("not matched!") + end end '; } --- request GET /re ---- response_body_like: 500 Internal Server Error ---- error_code: 500 ---- error_log chop -lua entry thread aborted: runtime error: [string "content_by_lua"]:2: bad argument #2 to 'match' (failed to compile regex "([0-9]+": pcre_compile() failed: missing ) in "([0-9]+") +--- response_body +error: failed to compile regex "([0-9]+": pcre_compile() failed: missing ) in "([0-9]+" + +--- no_error_log +[error] @@ -902,3 +913,35 @@ nil --- no_error_log [error] + + +=== TEST 42: bad UTF-8 +--- config + location = /t { + content_by_lua ' + local target = "你好" + local regex = "你好" + + -- Note the D here + local m, err = ngx.re.match(string.sub(target, 1, 4), regex, "u") + + if err then + ngx.say("error: ", err) + return + end + + if m then + ngx.say("matched: ", m[0]) + else + ngx.say("not matched") + end + '; + } +--- request +GET /t +--- response_body_like chop +error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" + +--- no_error_log +[error] + diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 2d66de425d..2661cdfb93 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(5); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 3); our $HtmlDir = html_dir; @@ -681,3 +681,63 @@ not matched! 1234 + + +=== TEST 26: bad pattern +--- config + location /re { + content_by_lua ' + local it, err = ngx.re.gmatch("hello\\nworld", "(abc") + if not err then + ngx.say("good") + + else + ngx.say("error: ", err) + end + '; + } +--- request + GET /re +--- response_body +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] + + + +=== TEST 27: bad UTF-8 +--- config + location = /t { + content_by_lua ' + local target = "你好" + local regex = "你好" + + -- Note the D here + local it, err = ngx.re.gmatch(string.sub(target, 1, 4), regex, "u") + + if err then + ngx.say("error: ", err) + return + end + + local m, err = it() + if err then + ngx.say("error: ", err) + return + end + + if m then + ngx.say("matched: ", m[0]) + else + ngx.say("not matched") + end + '; + } +--- request +GET /t +--- response_body_like chop +error: pcre_exec\(\) failed: -10 on "你.*?" + +--- no_error_log +[error] + diff --git a/t/036-sub.t b/t/036-sub.t index 60727ab0d3..43f883028e 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 9); #no_diff(); no_long_string(); @@ -72,19 +72,22 @@ a [b c] [b] [c] [] [] d --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "a b c d", + local s, n, err = ngx.re.sub("a b c d", "(b) (c)", "[$0] [$1] [$2] [$3] [$hello]") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + if s then + ngx.say(s, ": ", n) + + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" -nil +error: bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" +--- error_log +attempt to use named capturing variable "hello" (named captures not supported yet) @@ -92,19 +95,21 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "a b c d", + local s, n, err = ngx.re.sub("a b c d", "(b) (c)", "[$0] [$1] [$2] [$3] [${hello}]") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" -nil +error: bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" +--- error_log +attempt to use named capturing variable "hello" (named captures not supported yet) @@ -129,18 +134,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134]") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134]") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" +--- error_log +the closing bracket in "134" variable is missing @@ -148,18 +155,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" +--- error_log +the closing bracket in "134" variable is missing @@ -167,18 +176,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${" +--- error_log +lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" @@ -186,18 +197,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [$") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [$") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [$" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [$" +--- error_log +lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [$" @@ -445,3 +458,52 @@ a [b c] [b] [c] [] [] d --- no_error_log [error] + + +=== TEST 24: bad pattern +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.sub("hello\\nworld", "(abc", "") + if s then + ngx.say("subs: ", n) + + else + ngx.say("error: ", err) + end + '; + } +--- request + GET /re +--- response_body +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] + + + +=== TEST 25: bad UTF-8 +--- config + location = /t { + content_by_lua ' + local target = "你好" + local regex = "你好" + + -- Note the D here + local s, n, err = ngx.re.sub(string.sub(target, 1, 4), regex, "", "u") + + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end + '; + } +--- request +GET /t +--- response_body_like chop +error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" + +--- no_error_log +[error] + diff --git a/t/037-gsub.t b/t/037-gsub.t index 7b9bf3055d..9a26390f53 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 9); +plan tests => repeat_each() * (blocks() * 2 + 10); #no_diff(); no_long_string(); @@ -403,3 +403,30 @@ n: 1 --- no_error_log [error] + + +=== TEST 20: bad UTF-8 +--- config + location = /t { + content_by_lua ' + local target = "你好" + local regex = "你好" + + -- Note the D here + local s, n, err = ngx.re.gsub(string.sub(target, 1, 4), regex, "", "u") + + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end + '; + } +--- request +GET /t +--- response_body_like chop +error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" + +--- no_error_log +[error] + diff --git a/t/038-match-o.t b/t/038-match-o.t index c96683ad0e..494f9f564d 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 3); #no_diff(); #no_long_string(); @@ -321,22 +321,26 @@ he --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", "(abc", "o") - if rc then - if m then - ngx.say(m[0]) + local m, err = ngx.re.match("hello\\nworld", "(abc", "o") + if m then + ngx.say(m[0]) + + else + if err then + ngx.say("error: ", err) + else ngx.say("not matched: ", m) end - else - ngx.say("error: ", m) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/039-sub-o.t b/t/039-sub-o.t index 2eb894e11a..5b7e573e1d 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); no_long_string(); @@ -68,23 +68,28 @@ a [b c] [b] [c] [] [] d -=== TEST 4: matched and with named variables +=== TEST 4: matched and with named variables (bad template) --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "a b c d", - "(b) (c)", "[$0] [$1] [$2] [$3] [$hello]", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("a b c d", + "(b) (c)", + "[$0] [$1] [$2] [$3] [$hello]", + "o") + if s then + ngx.say(s, ": ", n) + + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" -nil +error: bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" +--- error_log +attempt to use named capturing variable "hello" (named captures not supported yet) @@ -92,19 +97,23 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "a b c d", - "(b) (c)", "[$0] [$1] [$2] [$3] [${hello}]", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("a b c d", + "(b) (c)", + "[$0] [$1] [$2] [$3] [${hello}]", + "o") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" -nil +error: bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" +--- error_log +attempt to use named capturing variable "hello" (named captures not supported yet) @@ -129,18 +138,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134]", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134]", "o") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" +--- error_log +the closing bracket in "134" variable is missing @@ -148,18 +159,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${134", "o") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" +--- error_log +the closing bracket in "134" variable is missing @@ -167,18 +180,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [${", "o") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [${" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${" +--- error_log +lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" @@ -186,18 +201,20 @@ nil --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [$", "o") - ngx.say(rc) - ngx.say(s) - ngx.say(n) + local s, n, err = ngx.re.sub("b c d", "(b) (c)", "[$0] [$1] [${2}] [$3] [$", "o") + if s then + ngx.say(s, ": ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false -bad template for substitution: "[$0] [$1] [${2}] [$3] [$" -nil +error: bad template for substitution: "[$0] [$1] [${2}] [$3] [$" +--- error_log +lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [$" diff --git a/t/047-match-jit.t b/t/047-match-jit.t index 74a75088a1..ff1f59c65a 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); no_long_string(); @@ -105,20 +105,24 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.match, "hello\\nworld", "(abc", "j") - if rc then - if m then - ngx.say(m[0]) + local m, err = ngx.re.match("hello\\nworld", "(abc", "j") + if m then + ngx.say(m[0]) + + else + if err then + ngx.say("error: ", err) + else ngx.say("not matched: ", m) end - else - ngx.say("error: ", m) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t index 56840b247f..401659ce99 100644 --- a/t/049-gmatch-jit.t +++ b/t/049-gmatch-jit.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 9); #no_diff(); #no_long_string(); @@ -197,8 +197,8 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - rc, err = pcall(ngx.re.gmatch, "hello\\nworld", "(abc", "j") - if not rc then + local m, err = ngx.re.gmatch("hello\\nworld", "(abc", "j") + if not m then ngx.say("error: ", err) return end @@ -208,5 +208,7 @@ pcre JIT compiling result: 1 --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index a4b236f86b..28492763bc 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 1); #no_diff(); #no_long_string(); @@ -202,8 +202,8 @@ hello --- config location /re { content_by_lua ' - rc, err = pcall(ngx.re.gmatch, "hello\\nworld", "(abc", "d") - if not rc then + local it, err = ngx.re.gmatch("hello\\nworld", "(abc", "d") + if not it then ngx.say("error: ", err) return end @@ -213,5 +213,7 @@ hello --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/051-sub-jit.t b/t/051-sub-jit.t index 7c728f8d70..c32fd96e43 100644 --- a/t/051-sub-jit.t +++ b/t/051-sub-jit.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); no_long_string(); @@ -105,18 +105,20 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "hello\\nworld", "(abc", "world", "j") - if rc then + local s, n, err = ngx.re.sub("hello\\nworld", "(abc", "world", "j") + if s then ngx.say(s, ": ", n) else - ngx.say("error: ", s) + ngx.say("error: ", err) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] @@ -124,16 +126,18 @@ error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() fa --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.sub, "hello\\nworld", "(abc", "world", "jo") - if rc then + local s, n, err = ngx.re.sub( "hello\\nworld", "(abc", "world", "jo") + if s then ngx.say(s, ": ", n) else - ngx.say("error: ", s) + ngx.say("error: ", err) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index 0600619c64..62e3b07bde 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); no_long_string(); @@ -97,14 +97,21 @@ hello, world: 0 --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.sub, "hello\\nworld", "(abc", "world", "j") - ngx.say(rc, ": ", m) + local s, n, err = ngx.re.sub("hello\\nworld", "(abc", "world", "j") + if s then + ngx.say(s, ": ", n) + + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] @@ -112,12 +119,19 @@ false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() fa --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.sub, "hello\\nworld", "(abc", "world", "jo") - ngx.say(rc, ": ", m) + local s, n, err = ngx.re.sub("hello\\nworld", "(abc", "world", "jo") + if s then + ngx.say(s, ": ", n) + + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/053-gsub-jit.t b/t/053-gsub-jit.t index 5ef6f5bf20..c1b3cd219f 100644 --- a/t/053-gsub-jit.t +++ b/t/053-gsub-jit.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); no_long_string(); @@ -105,18 +105,20 @@ pcre JIT compiling result: 1 --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.gsub, "hello\\nworld", "(abc", "world", "j") - if rc then + local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "j") + if s then ngx.say(s, ": ", n) else - ngx.say("error: ", s) + ngx.say("error: ", err) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] @@ -124,16 +126,18 @@ error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() fa --- config location /re { content_by_lua ' - local rc, s, n = pcall(ngx.re.gsub, "hello\\nworld", "(abc", "world", "jo") - if rc then + local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "jo") + if s then ngx.say(s, ": ", n) else - ngx.say("error: ", s) + ngx.say("error: ", err) end '; } --- request GET /re --- response_body -error: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index 92d05df2c1..21f55a3fa0 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 1); #no_diff(); no_long_string(); @@ -97,14 +97,19 @@ hello, world: 0 --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.gsub, "hello\\nworld", "(abc", "world", "j") - ngx.say(rc, ": ", m) + local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "j") + if s then + ngx.say("gsub: ", n) + + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" @@ -112,12 +117,18 @@ false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() fa --- config location /re { content_by_lua ' - rc, m = pcall(ngx.re.gsub, "hello\\nworld", "(abc", "world", "jo") - ngx.say(rc, ": ", m) + local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "jo") + if s then + ngx.say("gsub: ", n) + else + ngx.say("error: ", err) + end '; } --- request GET /re --- response_body -false: bad argument #2 to '?' (failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc") +error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +--- no_error_log +[error] From 0c8fb04d6baecc4d54a1f13b73f23f69a4e68bbb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 18 Mar 2013 00:00:42 -0700 Subject: [PATCH 0035/1981] one minor coding style fix. --- src/ngx_http_lua_subrequest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index b95e365aaf..03493536bd 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -400,8 +400,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "Bad http request body"); } - body = ngx_pcalloc(r->pool, - sizeof(ngx_http_request_body_t)); + body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "out of memory"); From d3c549e9f5ad4d847a3224a8e3f80b937120fe5c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 18 Mar 2013 00:07:18 -0700 Subject: [PATCH 0036/1981] bugfix: (large) in-file request bodies could not be inherited correctly by multiple subrequests issued by ngx.location.capture. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_subrequest.c | 48 ++++++++++ t/020-subrequest.t | 164 +++++++++++++++++++++++++++++++++- 2 files changed, 211 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index b95e365aaf..2dc43d5b6a 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -59,6 +59,7 @@ static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r); static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r); +static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r); /* ngx.location.capture is just a thin wrapper around @@ -606,6 +607,16 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, #if 1 sr->request_body = NULL; #endif + + } else if (sr->request_body) { + + /* deep-copy the request body */ + + if (sr->request_body->temp_file) { + if (ngx_http_lua_copy_in_file_request_body(sr) != NGX_OK) { + return NGX_ERROR; + } + } } sr->method = method; @@ -1545,4 +1556,41 @@ ngx_http_post_request_to_head(ngx_http_request_t *r) return NGX_OK; } + +static ngx_int_t +ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r) +{ + ngx_temp_file_t *tf; + + ngx_http_request_body_t *body; + + tf = r->request_body->temp_file; + + if (!tf->persistent || !tf->clean) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the request body was not read by ngx_lua"); + + return NGX_ERROR; + } + + body = ngx_palloc(r->pool, sizeof(ngx_http_request_body_t)); + if (body == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(body, r->request_body, sizeof(ngx_http_request_body_t)); + + body->temp_file = ngx_palloc(r->pool, sizeof(ngx_temp_file_t)); + if (body->temp_file == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(body->temp_file, tf, sizeof(ngx_temp_file_t)); + dd("file fd: %d", body->temp_file->file.fd); + + r->request_body = body; + + return NGX_OK; +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 921bdb0630..669d68783d 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 10); +plan tests => repeat_each() * (blocks() * 3 + 11); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -1689,3 +1689,165 @@ body: hello world --- 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 + From dfc7a4cd71598316413c7766445886353be971ab Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 19 Mar 2013 21:38:45 -0700 Subject: [PATCH 0037/1981] feature: datagram unix domain sockets created by ngx.socket.udp() can now receive data from the other endpoint via "autobind" on Linux. thanks Dirk Feytons for the patch. --- config | 11 ++++++ src/ngx_http_lua_socket_udp.c | 20 +++++++++++ t/087-udp-socket.t | 68 +++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/config b/config index 2117c31132..0eb8b11893 100644 --- a/config +++ b/config @@ -296,6 +296,17 @@ USE_SHA1=YES CORE_INCS="$CORE_INCS $ngx_addon_dir/src/api" +ngx_feature="SO_PASSCRED" +ngx_feature_libs= +ngx_feature_name="NGX_HTTP_LUA_HAVE_SO_PASSCRED" +ngx_feature_run=no +ngx_feature_incs="#include +#include " +ngx_feature_path= +ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' + +. auto/feature + #CFLAGS=$"$CFLAGS -DLUA_DEFAULT_PATH='\"/usr/local/openresty/lualib/?.lua\"'" #CFLAGS=$"$CFLAGS -DLUA_DEFAULT_CPATH='\"/usr/local/openresty/lualib/?.so\"'" diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 5d787c77d6..378cc9bbd5 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -624,6 +624,26 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_OK */ + /* + * TODO: we should accept an extra argument to setpeername() + * to allow the user bind the datagram unix domain socket herself, + * which is necessary for systems without autobind support. + */ + +#if (NGX_HTTP_LUA_HAVE_SO_PASSCRED) + if (uc->sockaddr->sa_family == AF_UNIX) { + int value = 1; + + if (setsockopt(uc->connection->fd, SOL_SOCKET, SO_PASSCRED, &value, + sizeof(value)) + != 0) + { + u->socket_errno = ngx_socket_errno; + return ngx_http_lua_socket_error_retval_handler(r, u, L); + } + } +#endif + c = uc->connection; c->data = u; diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 04b74a8bc2..535c35a6af 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -16,6 +16,7 @@ log_level 'warn'; no_long_string(); #no_diff(); +#no_shuffle(); run_tests(); @@ -726,3 +727,70 @@ successfully connected to xxx! --- no_error_log [error] + + +=== 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] +--- skip_eval: 3: $^O ne 'linux' + From b582064ecc0fe6713ba98d4f963452a2397abc72 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 20 Mar 2013 12:46:23 -0700 Subject: [PATCH 0038/1981] bugfix: when a non-table value was specified for the "args" option in the ngx.location.capture or ngx.location.capture_multi call, memory invalid access might happen, which resulted in garbage data at least. thanks Siddon Tang for reporting this issue. --- src/ngx_http_lua_subrequest.c | 12 +++++++- t/105-pressure.t | 55 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 t/105-pressure.t diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 03493536bd..e5202973c7 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -470,7 +470,17 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) } if (args.len == 0) { - args = extra_args; + if (extra_args.len) { + p = ngx_palloc(r->pool, extra_args.len); + if (p == NULL) { + return luaL_error(L, "out of memory"); + } + + ngx_memcpy(p, extra_args.data, extra_args.len); + + args.data = p; + args.len = extra_args.len; + } } else if (extra_args.len) { /* concatenate the two parts of args together */ diff --git a/t/105-pressure.t b/t/105-pressure.t new file mode 100644 index 0000000000..ba516b0998 --- /dev/null +++ b/t/105-pressure.t @@ -0,0 +1,55 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#log_level('debug'); + +repeat_each(20); + +plan tests => repeat_each() * (blocks() * 3); + +our $HtmlDir = html_dir; +#warn $html_dir; + +our $Id; + +#no_diff(); +#no_long_string(); + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +#no_shuffle(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: memory issue in the "args" string option for ngx.location.capture +--- config + location /test1 { + content_by_lua ' + local res = ngx.location.capture("/test2/auth", {args = ngx.var.args}) + ngx.print(res.body) + '; + } + location /test2 { + content_by_lua ' + collectgarbage() + ngx.say(ngx.var.args) + '; + } + +--- request eval +$::Id = int rand 10000; +"GET /test1?parent=$::Id&name=2013031816214284300707&footprint=dsfasfwefklds" + +--- response_body eval +"parent=$::Id&name=2013031816214284300707&footprint=dsfasfwefklds\n" + +--- no_error_log +[error] + From f4ffb4f932739483f55ed671c150da3d244a4eab Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 20 Mar 2013 12:47:12 -0700 Subject: [PATCH 0039/1981] one minor coding style fix. --- src/ngx_http_lua_control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 4c6a0471f5..b71b5931c2 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -161,6 +161,7 @@ ngx_http_lua_ngx_exec(lua_State *L) if (user_args.len) { if (args.len == 0) { args = user_args; + } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { From dbde4c390769c56fb2669e4cd083273e6a903918 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 20 Mar 2013 17:21:16 -0700 Subject: [PATCH 0040/1981] optimize: fixed the initial size of the ngx.shared table and also updated the tests accordingly. --- src/ngx_http_lua_shdict.c | 2 +- t/062-count.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index b5cec33374..e4caac13ce 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -291,7 +291,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 0, lmcf->shm_zones->nelts /* nrec */); /* ngx.shared */ - lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* shared mt */ + lua_createtable(L, 0 /* narr */, 12 /* nrec */); /* shared mt */ lua_pushcfunction(L, ngx_http_lua_shdict_get); lua_setfield(L, -2, "get"); diff --git a/t/062-count.t b/t/062-count.t index 544d909e25..61ba2f8284 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -279,7 +279,7 @@ n = 4 --- request GET /test --- response_body -n = 10 +n = 12 --- no_error_log [error] From 57e3a3a9fa29c00af45f2691efc96f9d722f199c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 20 Mar 2013 19:08:18 -0700 Subject: [PATCH 0041/1981] added a test case for github issue #218, which requires the run_posted_requests_in_resolver patch for the nginx core to get passed. --- t/014-bugs.t | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index cf16849340..4b03b29d31 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -9,7 +9,7 @@ log_level('debug'); repeat_each(3); -plan tests => repeat_each() * (blocks() * 2 + 22); +plan tests => repeat_each() * (blocks() * 2 + 23); our $HtmlDir = html_dir; #warn $html_dir; @@ -771,3 +771,47 @@ See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-Janua --- error_log eval qr/recv\(\) failed \(\d+: Connection refused\) while resolving/ + + +=== TEST 35: github issue #218: ngx.location.capture hangs when querying a remote host that does not exist or is really slow to respond +--- config + set $myurl "https://not-exist.agentzh.org"; + location /toto { + content_by_lua ' + local cjson = require "cjson" + local proxyUrl = "/myproxy/entity" + local res = ngx.location.capture( proxyUrl, { method = ngx.HTTP_GET }) + ngx.say("Hello, " .. cjson.encode(res)) + '; + } + location ~ /myproxy { + + rewrite ^/myproxy/(.*) /$1 break; + resolver_timeout 1s; + #resolver 172.16.0.23; # AWS DNS resolver address is the same in all regions - 172.16.0.23 + resolver 8.8.8.8; + proxy_read_timeout 1s; + proxy_send_timeout 1s; + proxy_connect_timeout 1s; + proxy_pass $myurl:443; + proxy_pass_request_body off; + proxy_set_header Content-Length 0; + proxy_set_header Accept-Encoding ""; + } + +--- request +GET /toto + +--- stap2 +F(ngx_http_lua_post_subrequest) { + println("lua post subrequest") + print_ubacktrace() +} + +--- response_body +Hello, {"status":502,"body":"","header":{"Content-Length":0}} + +--- error_log +not-exist.agentzh.org could not be resolved +--- timeout: 3 + From a38ceeb00239ce3e4c0279d5c7da573ae0d6e03b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 21 Mar 2013 12:00:58 -0700 Subject: [PATCH 0042/1981] optimize: we now use the bind() call to do autobind for datagram unix domain sockets in ngx.socket.udp() on Linux instead of abusing the side effect of SO_PASSCRED. thanks Dirk Feytons for the suggestion. --- src/ngx_http_lua_socket_udp.c | 47 ++++++++++++++++++++--------------- t/087-udp-socket.t | 3 ++- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 378cc9bbd5..bf1d6a4ba8 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -169,6 +169,12 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_http_lua_socket_udp_upstream_t *u; + /* + * TODO: we should probably accept an extra argument to setpeername() + * to allow the user bind the datagram unix domain socket himself, + * which is necessary for systems without autobind support. + */ + n = lua_gettop(L); if (n != 2 && n != 3) { return luaL_error(L, "ngx.socket.udp setpeername: expecting 2 or 3 " @@ -624,26 +630,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_OK */ - /* - * TODO: we should accept an extra argument to setpeername() - * to allow the user bind the datagram unix domain socket herself, - * which is necessary for systems without autobind support. - */ - -#if (NGX_HTTP_LUA_HAVE_SO_PASSCRED) - if (uc->sockaddr->sa_family == AF_UNIX) { - int value = 1; - - if (setsockopt(uc->connection->fd, SOL_SOCKET, SO_PASSCRED, &value, - sizeof(value)) - != 0) - { - u->socket_errno = ngx_socket_errno; - return ngx_http_lua_socket_error_retval_handler(r, u, L); - } - } -#endif - c = uc->connection; c->data = u; @@ -1348,6 +1334,27 @@ ngx_http_lua_udp_connect(ngx_udp_connection_t *uc) #endif +#if (NGX_HTTP_LUA_HAVE_SO_PASSCRED) + if (uc->sockaddr->sa_family == AF_UNIX) { + struct sockaddr addr; + + addr.sa_family = AF_UNIX; + + /* just to make valgrind happy */ + ngx_memzero(addr.sa_data, sizeof(addr.sa_data)); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "datagram unix " + "domain socket autobind"); + + if (bind(uc->connection->fd, &addr, sizeof(sa_family_t)) != 0) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + "bind() failed"); + + return NGX_ERROR; + } + } +#endif + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 535c35a6af..14da9f5d20 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 6); +plan tests => repeat_each() * (3 * blocks() + 7); our $HtmlDir = html_dir; @@ -792,5 +792,6 @@ probe syscall.socket.return, syscall.connect.return { } --- no_error_log [error] +[crit] --- skip_eval: 3: $^O ne 'linux' From 16db13b8871d3a67826b4a86e9f8465e22ba7bf8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 21 Mar 2013 19:31:14 -0700 Subject: [PATCH 0043/1981] eliminated the use of the cjson library in a recently-added test case. --- t/014-bugs.t | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index 4b03b29d31..1970deab1b 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -778,10 +778,9 @@ qr/recv\(\) failed \(\d+: Connection refused\) while resolving/ set $myurl "https://not-exist.agentzh.org"; location /toto { content_by_lua ' - local cjson = require "cjson" local proxyUrl = "/myproxy/entity" local res = ngx.location.capture( proxyUrl, { method = ngx.HTTP_GET }) - ngx.say("Hello, " .. cjson.encode(res)) + ngx.say("Hello, ", res.status) '; } location ~ /myproxy { @@ -809,7 +808,7 @@ F(ngx_http_lua_post_subrequest) { } --- response_body -Hello, {"status":502,"body":"","header":{"Content-Length":0}} +Hello, 502 --- error_log not-exist.agentzh.org could not be resolved From 7f94cb208c7a059a4c070efae43b1faad78671af Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 23 Mar 2013 00:39:32 -0700 Subject: [PATCH 0044/1981] fixed some test cases which may fail in slow testing modes. --- t/023-rewrite/client-abort.t | 1 + t/024-access/client-abort.t | 1 + t/100-client-abort.t | 1 + 3 files changed, 3 insertions(+) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index e7f1becd8e..093fe0e20a 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -384,6 +384,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.2 --- abort --- ignore_response diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index d070346e5b..d995361d40 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -384,6 +384,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.2 --- abort --- ignore_response diff --git a/t/100-client-abort.t b/t/100-client-abort.t index f1ff0655a9..e1b3761e70 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -381,6 +381,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.2 --- abort --- ignore_response From 84c4d1833954674e772b3d7662b9495d5f0ae144 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 23 Mar 2013 22:44:28 -0700 Subject: [PATCH 0045/1981] bugfix: ngx.socket.udp: memory leaks or invalid memory accesses might happen when the DNS resolver failed to resolve. --- src/ngx_http_lua_socket_udp.c | 5 +++++ t/087-udp-socket.t | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index bf1d6a4ba8..b19d515a18 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -461,6 +461,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) ngx_resolver_strerror(ctx->state)); lua_concat(L, 2); +#if 1 + ur->ctx = NULL; + ngx_resolve_name_done(ctx); +#endif + u->prepare_retvals = ngx_http_lua_socket_error_retval_handler; ngx_http_lua_socket_udp_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_RESOLVER); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 14da9f5d20..de4edaf110 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -5,14 +5,14 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 7); +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'; +#log_level 'warn'; no_long_string(); #no_diff(); @@ -679,7 +679,16 @@ lua udp socket receive buffer size: 8192 '; } --- request -GET /lua +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 From 357f25d10a649c65cdb6abbbac77d5be01c39f56 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 24 Mar 2013 11:10:29 -0700 Subject: [PATCH 0046/1981] added a (passing) test for ensuring the resolver gets shut down properly when it fails to resolve a domain. --- t/058-tcp-socket.t | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index d3911fb7b5..6f31e64f6c 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * 94; +plan tests => repeat_each() * 95; our $HtmlDir = html_dir; @@ -2015,6 +2015,16 @@ close: 1 nil } --- request GET /lua + +--- stap +F(ngx_resolve_name_done) { + println("resolve name done") + #print_ubacktrace() +} + +--- stap_out +resolve name done + --- response_body_like chop ^failed to connect to xxx: xxx could not be resolved.*?Host not found From 168eb3878baf04df4fc8281ab603039236b1f53a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 24 Mar 2013 11:11:02 -0700 Subject: [PATCH 0047/1981] typo fixes in the tests for udp cosockets. --- t/087-udp-socket.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index de4edaf110..db36b9246b 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -255,7 +255,7 @@ end --- stap2 M(http-lua-info) { - printf("tcp resume: %p\n", $coctx) + printf("udp resume: %p\n", $coctx) print_ubacktrace() } @@ -501,7 +501,7 @@ lua udp socket receive buffer size: 1400 -=== TEST 9: read timeout and resend +=== TEST 9: read timeout and re-receive --- config location = /t { content_by_lua ' From c7879f30fb81428143fe9b2f6238e0bdd44f1c15 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 24 Mar 2013 17:39:55 -0700 Subject: [PATCH 0048/1981] raised the error log level back to "warn" for 087-udp-socket.t, which contains test cases that can flush error logs a lot which may lead to timeouts. --- t/087-udp-socket.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index db36b9246b..3b1891d442 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -12,7 +12,7 @@ our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; -#log_level 'warn'; +log_level 'warn'; no_long_string(); #no_diff(); From 5193cff298c611251c07fcd8dcef3ed2e4efd429 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 24 Mar 2013 22:15:48 -0700 Subject: [PATCH 0049/1981] updated docs to reflect recent changes. --- README | 32 +++++++++++++++++--------------- README.markdown | 16 +++++++--------- doc/HttpLuaModule.wiki | 22 ++++++++++------------ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/README b/README index 57e4f395c8..5769a86be2 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.17 - () released on 10 + This document describes ngx_lua v0.7.18 + () released on 24 March 2013. Synopsis @@ -3560,7 +3560,7 @@ Nginx API for Lua Only the first occurrence of the match is returned, or "nil" if no match is found. In case of errors, like seeing a bad regular expression or - exceeding the PCRE stack limit, `nil` and a string describing the error + exceeding the PCRE stack limit, "nil" and a string describing the error will be returned. When a match is found, a Lua table "captures" is returned, where @@ -3649,10 +3649,10 @@ Nginx API for Lua These options can be combined: - local m = ngx.re.match("hello, world", "HEL LO", "ix") + local m, err = ngx.re.match("hello, world", "HEL LO", "ix") -- m[0] == "hello" - local m = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") + local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") -- m[0] == "hello, 美好" -- m[1] == "美好" @@ -3710,7 +3710,7 @@ Nginx API for Lua let the user programmer iterate all the matches over the "" string argument with the PCRE "regex". - In case of errors, like seeing an ill-formed regular expression, `nil` + In case of errors, like seeing an ill-formed regular expression, "nil" and a string describing the error will be returned. Here is a small example to demonstrate its basic usage: @@ -3791,7 +3791,7 @@ Nginx API for Lua This method returns the resulting new string as well as the number of successful substitutions. In case of failures, like syntax errors in the regular expressions or the "" string argument, it will return - `nil` and a string describing the error. + "nil" and a string describing the error. When the "replace" is a string, then it is treated as a special template for string replacement. For example, @@ -3800,7 +3800,6 @@ Nginx API for Lua if newstr then -- newstr == "hello, [12][1]34" -- n == 1 - else ngx.log(ngx.ERR, "error: ", err) return @@ -3848,7 +3847,8 @@ Nginx API for Lua This feature was first introduced in the "v0.2.1rc13" release. ngx.re.gsub - syntax: *newstr, n = ngx.re.gsub(subject, regex, replace, options?)* + syntax: *newstr, n, err = ngx.re.gsub(subject, regex, replace, + options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** @@ -3861,7 +3861,6 @@ Nginx API for Lua if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 - else ngx.log(ngx.ERR, "error: ", err) return @@ -4295,7 +4294,8 @@ Nginx API for Lua '; } - Connecting to a datagram unix domain socket file is also possible: + Since the "v0.7.18" release, connecting to a datagram unix domain socket + file is also possible on Linux: local sock = ngx.socket.udp() local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock") @@ -4305,7 +4305,8 @@ Nginx API for Lua end assuming the datagram service is listening on the unix domain socket - file "/tmp/some-datagram-service.sock". + file "/tmp/some-datagram-service.sock" and the client socket will use + the "autobind" feature on Linux. Calling this method on an already connected socket object will cause the original connection to be closed first. @@ -5400,9 +5401,10 @@ Data Sharing within an Nginx Worker worker process, encapsulate the shared data into a Lua module, use the Lua "require" builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded - only once and all coroutines will share the same copy of the module. - Note however that Lua global variables WILL NOT persist between requests - because of the one-coroutine-per-request isolation design. + only once and all coroutines will share the same copy of the module + (both its code and data). Note however that Lua global variables (note, + not module-level variables) WILL NOT persist between requests because of + the one-coroutine-per-request isolation design. Here is a complete small example: diff --git a/README.markdown b/README.markdown index 465e99b638..e5055af9be 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.17](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 March 2013. +This document describes ngx_lua [v0.7.18](https://github.com/chaoslawful/lua-nginx-module/tags) released on 24 March 2013. Synopsis ======== @@ -3390,12 +3390,12 @@ Specify `options` to control how the match operation will be performed. The foll These options can be combined: - local m = ngx.re.match("hello, world", "HEL LO", "ix") + local m, err = ngx.re.match("hello, world", "HEL LO", "ix") -- m[0] == "hello" - local m = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") + local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") -- m[0] == "hello, 美好" -- m[1] == "美好" @@ -3523,7 +3523,6 @@ When the `replace` is a string, then it is treated as a special template for str if newstr then -- newstr == "hello, [12][1]34" -- n == 1 - else ngx.log(ngx.ERR, "error: ", err) return @@ -3569,7 +3568,7 @@ This feature was first introduced in the `v0.2.1rc13` release. ngx.re.gsub ----------- -**syntax:** *newstr, n = ngx.re.gsub(subject, regex, replace, options?)* +**syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** @@ -3582,7 +3581,6 @@ Here is some examples: if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 - else ngx.log(ngx.ERR, "error: ", err) return @@ -3924,7 +3922,7 @@ Here is an example for connecting to a UDP (memcached) server: } -Connecting to a datagram unix domain socket file is also possible: +Since the `v0.7.18` release, connecting to a datagram unix domain socket file is also possible on Linux: local sock = ngx.socket.udp() @@ -3935,7 +3933,7 @@ Connecting to a datagram unix domain socket file is also possible: end -assuming the datagram service is listening on the unix domain socket file `/tmp/some-datagram-service.sock`. +assuming the datagram service is listening on the unix domain socket file `/tmp/some-datagram-service.sock` and the client socket will use the "autobind" feature on Linux. Calling this method on an already connected socket object will cause the original connection to be closed first. @@ -4818,7 +4816,7 @@ To force `curl` to send HTTP 1.0 requests, use the `-0` option. Data Sharing within an Nginx Worker =================================== -To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module. Note however that Lua global variables WILL NOT persist between requests because of the one-coroutine-per-request isolation design. +To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. Here is a complete small example: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b39126cfbb..bb77b98e83 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.17] released on 10 March 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.18] released on 24 March 2013. = Synopsis = @@ -3181,7 +3181,7 @@ Returns true if the current request is an nginx subrequest, or subject string using the Perl compatible regular expression regex with the optional options. -Only the first occurrence of the match is returned, or nil if no match is found. In case of errors, like seeing a bad regular expression or exceeding the PCRE stack limit, `nil` and a string describing the error will be returned. +Only the first occurrence of the match is returned, or nil if no match is found. In case of errors, like seeing a bad regular expression or exceeding the PCRE stack limit, nil and a string describing the error will be returned. When a match is found, a Lua table captures is returned, where captures[0] holds the whole substring being matched, and captures[1] holds the first parenthesized sub-pattern's capturing, captures[2] the second, and so on. @@ -3274,12 +3274,12 @@ Specify options to control how the match operation will be performe These options can be combined: - local m = ngx.re.match("hello, world", "HEL LO", "ix") + local m, err = ngx.re.match("hello, world", "HEL LO", "ix") -- m[0] == "hello" - local m = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") + local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu") -- m[0] == "hello, 美好" -- m[1] == "美好" @@ -3323,7 +3323,7 @@ This feature was introduced in the v0.2.1rc11 release. Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. -In case of errors, like seeing an ill-formed regular expression, `nil` and a string describing the error will be returned. +In case of errors, like seeing an ill-formed regular expression, nil and a string describing the error will be returned. Here is a small example to demonstrate its basic usage: @@ -3396,7 +3396,7 @@ This feature was first introduced in the v0.2.1rc12 release. Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. -This method returns the resulting new string as well as the number of successful substitutions. In case of failures, like syntax errors in the regular expressions or the string argument, it will return `nil` and a string describing the error. +This method returns the resulting new string as well as the number of successful substitutions. In case of failures, like syntax errors in the regular expressions or the string argument, it will return nil and a string describing the error. When the replace is a string, then it is treated as a special template for string replacement. For example, @@ -3405,7 +3405,6 @@ When the replace is a string, then it is treated as a special templ if newstr then -- newstr == "hello, [12][1]34" -- n == 1 - else ngx.log(ngx.ERR, "error: ", err) return @@ -3450,7 +3449,7 @@ This method requires the PCRE library enabled in Nginx. ([[#Special PCRE Sequen This feature was first introduced in the v0.2.1rc13 release. == ngx.re.gsub == -'''syntax:''' ''newstr, n = ngx.re.gsub(subject, regex, replace, options?)'' +'''syntax:''' ''newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)'' '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' @@ -3463,7 +3462,6 @@ Here is some examples: if newstr then -- newstr == "[hello,h], [world,w]" -- n == 2 - else ngx.log(ngx.ERR, "error: ", err) return @@ -3791,7 +3789,7 @@ Here is an example for connecting to a UDP (memcached) server: } -Connecting to a datagram unix domain socket file is also possible: +Since the v0.7.18 release, connecting to a datagram unix domain socket file is also possible on Linux: local sock = ngx.socket.udp() @@ -3802,7 +3800,7 @@ Connecting to a datagram unix domain socket file is also possible: end -assuming the datagram service is listening on the unix domain socket file /tmp/some-datagram-service.sock. +assuming the datagram service is listening on the unix domain socket file /tmp/some-datagram-service.sock and the client socket will use the "autobind" feature on Linux. Calling this method on an already connected socket object will cause the original connection to be closed first. @@ -4656,7 +4654,7 @@ To force curl to send HTTP 1.0 requests, use the -0 op = Data Sharing within an Nginx Worker = -To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua require builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module. Note however that Lua global variables WILL NOT persist between requests because of the one-coroutine-per-request isolation design. +To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua require builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. Here is a complete small example: From 664d74ed7fc6761efb1c07cb948f583ce54ddd81 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 26 Mar 2013 18:09:32 -0700 Subject: [PATCH 0050/1981] bugfix: ngx.req.raw_header() would return the first part of the request body when request body was read before the call. thanks Matthieu Tourne for reporting this issue. bugfix: ngx.req.raw_header() might not work properly in a subrequest. --- src/ngx_http_lua_headers.c | 64 +++++++++++--------- t/104-req-raw-header.t | 118 +++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 27 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index ce552ddc42..5e6c08de25 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -67,7 +67,7 @@ static int ngx_http_lua_ngx_req_raw_header(lua_State *L) { int n; - u_char *data, *p, *last; + u_char *data, *p, *last, *pos; unsigned no_req_line = 0, found; size_t size; ngx_buf_t *b, *first = NULL; @@ -91,7 +91,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } - hc = r->http_connection; + hc = r->main->http_connection; if (hc->nbusy) { b = NULL; /* to suppress a gcc warning */ @@ -100,8 +100,9 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) b = hc->busy[i]; if (first == NULL) { - if (r->request_line.data >= b->pos - || r->request_line.data + r->request_line.len + 2 + if (r->main->request_line.data >= b->pos + || r->main->request_line.data + + r->main->request_line.len + 2 <= b->start) { continue; @@ -111,27 +112,28 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) first = b; } - size += b->pos - b->start; - - if (b == r->header_in) { + if (b == r->main->header_in) { + size += r->main->header_end + 2 - b->start; break; } + + size += b->pos - b->start; } } else { - if (r != r->main) { - b = r->main->header_in; - - } else { - b = r->header_in; - } + b = r->main->header_in; if (b == NULL) { lua_pushnil(L); return 1; } - size = b->pos - r->request_line.data; + if (b == r->main->header_in) { + size = r->main->header_end + 2 - r->main->request_line.data; + + } else { + size = b->pos - r->main->request_line.data; + } } data = lua_newuserdata(L, size); @@ -153,26 +155,33 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) p = last; + if (b == r->main->header_in) { + pos = r->main->header_end + 2; + + } else { + pos = b->pos; + } + if (b == first) { - dd("request line: %.*s", (int) r->request_line.len, - r->request_line.data); + dd("request line: %.*s", (int) r->main->request_line.len, + r->main->request_line.data); if (no_req_line) { last = ngx_copy(last, - r->request_line.data + r->request_line.len - + 2, - b->pos - r->request_line.data - - r->request_line.len - 2); + r->main->request_line.data + + r->main->request_line.len + 2, + pos - r->main->request_line.data + - r->main->request_line.len - 2); } else { last = ngx_copy(last, - r->request_line.data, - b->pos - r->request_line.data); + r->main->request_line.data, + pos - r->main->request_line.data); } } else { - last = ngx_copy(last, b->start, b->pos - b->start); + last = ngx_copy(last, b->start, pos - b->start); } #if 1 @@ -197,7 +206,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } } - if (b == r->header_in) { + if (b == r->main->header_in) { break; } } @@ -205,11 +214,12 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } else { if (no_req_line) { last = ngx_copy(data, - r->request_line.data + r->request_line.len + 2, - size - r->request_line.len - 2); + r->main->request_line.data + + r->main->request_line.len + 2, + size - r->main->request_line.len - 2); } else { - last = ngx_copy(data, r->request_line.data, size); + last = ngx_copy(data, r->main->request_line.data, size); } for (p = data; p != last; p++) { diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index 031947a79c..592c7589a1 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -364,3 +364,121 @@ Connection: close\r [error] --- timeout: 5 + + +=== TEST 14: small header (POST body) +--- config + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } +--- request +POST /t +hello +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 15: small header (POST body) - in subrequests +--- config + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } + location /main { + content_by_lua ' + local res = ngx.location.capture("/t") + ngx.print(res.body) + '; + } + +--- request +POST /main +hello +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: Close\r +Content-Length: 5\r +\r +} +--- no_error_log +[error] + + + +=== TEST 16: large header (POST body) +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } +--- request +POST /t +hello +--- more_headers eval +CORE::join"\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 17: large header (POST body) - in subrequests +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 561; + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } + + location /main { + content_by_lua ' + local res = ngx.location.capture("/t") + ngx.print(res.body) + '; + } +--- request +POST /main +hello +--- more_headers eval +CORE::join"\n", map { "Header$_: value-$_" } 1..512 + +--- response_body eval +qq{POST /main HTTP/1.1\r +Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + From f203b5f460a6b4e50a085803524494af8b304e35 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 26 Mar 2013 22:34:55 -0700 Subject: [PATCH 0051/1981] ngx.req.raw_header: added a buffer size assertion and two more (passing) tests regarding some special cases. --- src/ngx_http_lua_headers.c | 4 +++ t/104-req-raw-header.t | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 5e6c08de25..a7a03a14f9 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -234,6 +234,10 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } } + if (last - data > (ssize_t) size) { + return luaL_error(L, "buffer error"); + } + lua_pushlstring(L, (char *) data, last - data); return 1; } diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index 592c7589a1..cf75914851 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -482,3 +482,63 @@ Connection: Close\r [error] --- timeout: 5 + + +=== TEST 18: large header (POST body) - r->header_end is outside r->header_in +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 564; + location /t { + content_by_lua ' + -- ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } +--- request +POST /t +hello +--- more_headers eval +CORE::join("\n", map { "Header$_: value-$_" } 1..80) . "\nA: abcdefghijklmnopqrs\n" + +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..80) +. "\r\nA: abcdefghijklmnopqrs\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 19: large header (POST body) - r->header_end is outside r->header_in (2) +--- config + client_header_buffer_size 10; + large_client_header_buffers 30 564; + location /t { + content_by_lua ' + -- ngx.req.read_body() + ngx.print(ngx.req.raw_header()) + '; + } +--- request +POST /t +hello +--- more_headers eval +CORE::join("\n", map { "Header$_: value-$_" } 1..52) . "\nA: abcdefghijklmnopqrs\n" + +--- response_body eval +qq{POST /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +} +.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..52) +. "\r\nA: abcdefghijklmnopqrs\r\nContent-Length: 5\r\n\r\n" + +--- no_error_log +[error] +--- timeout: 5 + From d4b8c7d84eda2594d13e7521fd763336a5250130 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 27 Mar 2013 12:41:19 -0700 Subject: [PATCH 0052/1981] bumped version to 0.7.19. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 5769a86be2..d9c967cc1b 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.18 - () released on 24 + This document describes ngx_lua v0.7.19 + () released on 27 March 2013. Synopsis diff --git a/README.markdown b/README.markdown index e5055af9be..e1cdecc58b 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.18](https://github.com/chaoslawful/lua-nginx-module/tags) released on 24 March 2013. +This document describes ngx_lua [v0.7.19](https://github.com/chaoslawful/lua-nginx-module/tags) released on 27 March 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index bb77b98e83..49db34f0ec 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.18] released on 24 March 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.19] released on 27 March 2013. = Synopsis = From 66e2ccbfae3bda08064627b0ac3ee59e82f313b0 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 29 Mar 2013 10:59:29 -0700 Subject: [PATCH 0053/1981] bugfix: assignment to ngx.status did not take effect when the response status line had already been generated (by ngx_proxy or others). thanks eqiuno for reporting this issue in #221. --- src/ngx_http_lua_misc.c | 1 + t/015-status.t | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 0f9960e409..79b48edba5 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -126,6 +126,7 @@ ngx_http_lua_ngx_set(lua_State *L) /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); + r->headers_out.status_line.len = 0; return 0; } diff --git a/t/015-status.t b/t/015-status.t index 89289d4d55..45624e8678 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -10,7 +10,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 3); #no_diff(); #no_long_string(); @@ -190,3 +190,29 @@ invalid request --- no_error_log [error] + + +=== TEST 12: github issue #221: cannot modify ngx.status for responses from ngx_proxy +--- config + location = /t { + proxy_pass http://127.0.0.1:$server_port/; + header_filter_by_lua ' + if ngx.status == 206 then + ngx.status = ngx.HTTP_OK + end + '; + } + +--- request +GET /t + +--- more_headers +Range: bytes=0-4 + +--- response_body chop + Date: Sun, 31 Mar 2013 12:12:10 -0700 Subject: [PATCH 0054/1981] feature: now we allow zero time argument in ngx.sleep(). --- src/ngx_http_lua_sleep.c | 6 ------ t/077-sleep.t | 26 +++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index cca9ae2461..9ddca0ebde 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -47,12 +47,6 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "invalid sleep duration \"%d\"", delay); } - if (delay == 0) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua sleep for 0ms"); - return 0; - } - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); diff --git a/t/077-sleep.t b/t/077-sleep.t index a3b13bcea3..faafc5c630 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 34; +plan tests => repeat_each() * 40; #no_diff(); #no_long_string(); @@ -212,3 +212,27 @@ hello world --- no_error_log [error] + + +=== TEST 9: sleep 0 +--- config + location /test { + content_by_lua ' + ngx.update_time() + local before = ngx.now() + ngx.sleep(0) + local now = ngx.now() + ngx.say("elapsed: ", now - before) + '; + } +--- request +GET /test +--- response_body_like chop +elapsed: 0 +--- error_log +lua ready to sleep for +lua sleep timer expired: "/test?" +lua sleep timer expired: "/test?" +--- no_error_log +[error] + From 2ac8d8943917b0a5fdbc39a9e2a30b4105f43e75 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 1 Apr 2013 23:36:50 -0700 Subject: [PATCH 0055/1981] feature: added new Lua API, ngx.timer.at(time, callback), for defining timers that can run the user callback as a Lua "light thread" (detached from the current request) after the time (in seconds) specified. also added new configure directives lua_max_pending_timers and lua_max_running_timers for limiting the number of pending timers and "running" timers. --- .gitignore | 2 + config | 2 + src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_args.c | 8 +- src/ngx_http_lua_common.h | 15 +- src/ngx_http_lua_contentby.c | 14 +- src/ngx_http_lua_contentby.h | 2 + src/ngx_http_lua_control.c | 5 +- src/ngx_http_lua_coroutine.c | 12 +- src/ngx_http_lua_headers.c | 15 + src/ngx_http_lua_misc.c | 8 + src/ngx_http_lua_module.c | 28 +- src/ngx_http_lua_output.c | 4 +- src/ngx_http_lua_req_body.c | 24 +- src/ngx_http_lua_req_method.c | 4 + src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_sleep.c | 4 +- src/ngx_http_lua_socket_tcp.c | 12 +- src/ngx_http_lua_socket_udp.c | 10 +- src/ngx_http_lua_subrequest.c | 4 +- src/ngx_http_lua_timer.c | 470 ++++++++ src/ngx_http_lua_timer.h | 20 + src/ngx_http_lua_uri.c | 2 + src/ngx_http_lua_uthread.c | 3 +- src/ngx_http_lua_util.c | 191 ++- src/ngx_http_lua_util.h | 21 + src/ngx_http_lua_variable.c | 4 + t/062-count.t | 28 +- t/106-timer.t | 2054 +++++++++++++++++++++++++++++++++ t/107-timer-errors.t | 1424 +++++++++++++++++++++++ t/108-timer-safe.t | 1399 ++++++++++++++++++++++ t/StapThread.pm | 2 + 32 files changed, 5742 insertions(+), 53 deletions(-) create mode 100644 src/ngx_http_lua_timer.c create mode 100644 src/ngx_http_lua_timer.h create mode 100644 t/106-timer.t create mode 100644 t/107-timer-errors.t create mode 100644 t/108-timer-safe.t diff --git a/.gitignore b/.gitignore index a0bf9c3f76..aae0b97fab 100644 --- a/.gitignore +++ b/.gitignore @@ -149,8 +149,10 @@ tre src/phase.[ch] src/probe.h src/uthread.[ch] +src/timer.[ch] *.plist lua +ttimer Makefile tsubreq tthread diff --git a/config b/config index 0eb8b11893..a7e13bc4cd 100644 --- a/config +++ b/config @@ -221,6 +221,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_req_method.c \ $ngx_addon_dir/src/ngx_http_lua_phase.c \ $ngx_addon_dir/src/ngx_http_lua_uthread.c \ + $ngx_addon_dir/src/ngx_http_lua_timer.c \ " NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ @@ -270,6 +271,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_phase.h \ $ngx_addon_dir/src/ngx_http_lua_probe.h \ $ngx_addon_dir/src/ngx_http_lua_uthread.h \ + $ngx_addon_dir/src/ngx_http_lua_timer.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index a70c421932..84c9aaa3ac 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -326,7 +326,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index abb5527c3b..523f25505b 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -42,6 +42,8 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + switch (lua_type(L, 1)) { case LUA_TNUMBER: case LUA_TSTRING: @@ -113,6 +115,8 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + lua_createtable(L, 0, 4); /* we copy r->args over to buf to simplify @@ -171,8 +175,10 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + if (r->discard_body) { - lua_createtable(L, 0, 4); + lua_createtable(L, 0, 0); return 1; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index f9192b7a03..71db542681 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -77,6 +77,7 @@ typedef struct { #define NGX_HTTP_LUA_CONTEXT_LOG 0x10 #define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x20 #define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x40 +#define NGX_HTTP_LUA_CONTEXT_TIMER 0x80 typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t; @@ -100,6 +101,12 @@ struct ngx_http_lua_main_conf_s { ngx_pool_t *pool; + ngx_int_t max_pending_timers; + ngx_int_t pending_timers; + + ngx_int_t max_running_timers; + ngx_int_t running_timers; + #if (NGX_PCRE) ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; @@ -271,10 +278,6 @@ struct ngx_http_lua_co_ctx_s { typedef struct ngx_http_lua_ctx_s { - uint8_t context; /* the current running directive context - (or running phase) for the current - Lua chunk */ - ngx_http_handler_pt resume_handler; ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ @@ -326,6 +329,10 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_posted_thread_t *posted_threads; + uint16_t context; /* the current running directive context + (or running phase) for the current + Lua chunk */ + unsigned run_post_subrequest:1; /* whether it has run post_subrequest (for subrequests only) */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 11deaee5bd..26dff47cb2 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -19,8 +19,6 @@ static void ngx_http_lua_content_phase_post_read(ngx_http_request_t *r); -static ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n); ngx_int_t @@ -220,7 +218,7 @@ ngx_http_lua_content_phase_post_read(ngx_http_request_t *r) if (ctx->waiting_more_body) { ctx->waiting_more_body = 0; - ngx_http_finalize_request(r, ngx_http_lua_content_handler(r)); + ngx_http_lua_finalize_request(r, ngx_http_lua_content_handler(r)); } else { r->main->count--; @@ -313,13 +311,15 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) } -static ngx_int_t +ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n) { ngx_int_t rc; ngx_http_lua_posted_thread_t *pt; + dd("run posted threads: %p", ctx->posted_threads); + for ( ;; ) { pt = ctx->posted_threads; if (pt == NULL) { @@ -331,6 +331,8 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co, (int) pt->co_ctx->co_status); + dd("posted thread status: %d", pt->co_ctx->co_status); + if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) { continue; } @@ -350,7 +352,7 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, if (rc == NGX_OK) { while (n > 0) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); n--; } @@ -375,7 +377,7 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, /* n > 1 */ do { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); } while (--n > 1); return NGX_DONE; diff --git a/src/ngx_http_lua_contentby.h b/src/ngx_http_lua_contentby.h index 349e1d334e..766baa6c9b 100644 --- a/src/ngx_http_lua_contentby.h +++ b/src/ngx_http_lua_contentby.h @@ -17,6 +17,8 @@ void ngx_http_lua_content_wev_handler(ngx_http_request_t *r); ngx_int_t ngx_http_lua_content_handler_file(ngx_http_request_t *r); ngx_int_t ngx_http_lua_content_handler_inline(ngx_http_request_t *r); ngx_int_t ngx_http_lua_content_handler(ngx_http_request_t *r); +ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L, + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n); #endif /* _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index b71b5931c2..b32f438f64 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -317,7 +317,8 @@ ngx_http_lua_ngx_exit(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); rc = (ngx_int_t) luaL_checkinteger(L, 1); @@ -378,6 +379,8 @@ ngx_http_lua_on_abort(lua_State *L) return luaL_error(L, "no request ctx found"); } + ngx_http_lua_check_fake_request2(L, r, ctx); + if (ctx->on_abort_co_ctx) { lua_pushnil(L); lua_pushliteral(L, "duplicate call"); diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 0895bfe28d..d92ed5d16f 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -74,7 +74,8 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); mt = lmcf->lua; @@ -142,7 +143,8 @@ ngx_http_lua_coroutine_resume(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); p_coctx = ctx->cur_co_ctx; if (p_coctx == NULL) { @@ -204,7 +206,8 @@ ngx_http_lua_coroutine_yield(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); coctx = ctx->cur_co_ctx; @@ -323,7 +326,8 @@ ngx_http_lua_coroutine_status(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 5e6c08de25..30ec31ba13 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -41,6 +41,8 @@ ngx_http_lua_ngx_req_http_version(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + switch (r->http_version) { case NGX_HTTP_VERSION_9: lua_pushnumber(L, 0.9); @@ -91,6 +93,8 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + hc = r->main->http_connection; if (hc->nbusy) { @@ -277,6 +281,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + lua_createtable(L, 0, 4); if (!raw) { @@ -352,6 +358,8 @@ ngx_http_lua_ngx_header_get(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); @@ -407,6 +415,11 @@ ngx_http_lua_ngx_header_set(lua_State *L) } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx"); + } + + ngx_http_lua_check_fake_request2(L, r, ctx); if (ctx->headers_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " @@ -562,6 +575,8 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + p = (u_char *) luaL_checklstring(L, 1, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 0f9960e409..48301b5f39 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -57,6 +57,7 @@ ngx_http_lua_ngx_get(lua_State *L) if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { + ngx_http_lua_check_fake_request(L, r); lua_pushnumber(L, (lua_Number) r->headers_out.status); return 1; } @@ -78,6 +79,11 @@ ngx_http_lua_ngx_get(lua_State *L) && ngx_strncmp(p, "headers_sent", sizeof("headers_sent") - 1) == 0) { ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx"); + } + + ngx_http_lua_check_fake_request2(L, r, ctx); dd("headers sent: %d", ctx->headers_sent); @@ -124,6 +130,8 @@ ngx_http_lua_ngx_set(lua_State *L) return 0; } + ngx_http_lua_check_fake_request2(L, r, ctx); + /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); return 0; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 96dd35de96..4d7ecc1b14 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -47,6 +47,20 @@ static ngx_conf_post_t ngx_http_lua_lowat_post = static ngx_command_t ngx_http_lua_cmds[] = { + { ngx_string("lua_max_running_timers"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, max_running_timers), + NULL }, + + { ngx_string("lua_max_pending_timers"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, max_pending_timers), + NULL }, + { ngx_string("lua_shared_dict"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, ngx_http_lua_shared_dict, @@ -489,6 +503,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->lua = NULL; * lmcf->lua_path = { 0, NULL }; * lmcf->lua_cpath = { 0, NULL }; + * lmcf->pending_timers = 0; + * lmcf->running_timers = 0; * lmcf->regex_cache_entries = 0; * lmcf->shm_zones = NULL; * lmcf->init_handler = NULL; @@ -505,6 +521,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; + lmcf->max_pending_timers = NGX_CONF_UNSET; + lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) lmcf->regex_cache_max_entries = NGX_CONF_UNSET; #endif @@ -519,14 +537,22 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) static char * ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) { -#if (NGX_PCRE) ngx_http_lua_main_conf_t *lmcf = conf; +#if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; } #endif + if (lmcf->max_pending_timers == NGX_CONF_UNSET) { + lmcf->max_pending_timers = 1024; + } + + if (lmcf->max_running_timers == NGX_CONF_UNSET) { + lmcf->max_running_timers = 256; + } + return NGX_CONF_OK; } diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index cbeb16f07c..327282aabe 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -713,14 +713,14 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } /* rc == NGX_ERROR || rc >= NGX_OK */ if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 3a4662bb30..2a24de685d 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -226,6 +226,8 @@ ngx_http_lua_ngx_req_discard_body(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + rc = ngx_http_discard_request_body(r); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -261,6 +263,8 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + if (r->request_body == NULL || r->request_body->temp_file || r->request_body->bufs == NULL) @@ -330,6 +334,8 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + if (r->request_body == NULL || r->request_body->temp_file == NULL) { lua_pushnil(L); return 1; @@ -382,6 +388,8 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } @@ -543,6 +551,8 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + ngx_http_lua_check_fake_request(L, r); + if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } @@ -641,6 +651,8 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + ngx_http_lua_check_fake_request(L, r); + if (r->request_body == NULL || r->request_body->buf == NULL || r->request_body->bufs == NULL) @@ -702,6 +714,12 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + if (r == NULL) { + return luaL_error(L, "no request"); + } + + ngx_http_lua_check_fake_request(L, r); + if (r->request_body == NULL || r->request_body->buf == NULL || r->request_body->bufs == NULL) @@ -832,6 +850,8 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } @@ -1131,12 +1151,12 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index 78e5663826..b2d0e3c27a 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -50,6 +50,8 @@ ngx_http_lua_ngx_req_get_method(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + lua_pushlstring(L, (char *) r->method_name.data, r->method_name.len); return 1; } @@ -78,6 +80,8 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) return luaL_error(L, "request object not found"); } + ngx_http_lua_check_fake_request(L, r); + r->method = method; switch (method) { diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index bab9fee2e2..bd0fd3baae 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -322,7 +322,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); if (rc == NGX_OK) { diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index cca9ae2461..a6558cdda9 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -175,12 +175,12 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 212b497aff..e24f9fe061 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -237,7 +237,8 @@ ngx_http_lua_socket_tcp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); @@ -297,7 +298,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); luaL_checktype(L, 1, LUA_TTABLE); @@ -3008,7 +3010,7 @@ ngx_http_lua_req_socket(lua_State *L) if (lua_gettop(L) != 0) { return luaL_error(L, "expecting zero arguments, but got %d", - lua_gettop(L)); + lua_gettop(L)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); @@ -4005,12 +4007,12 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c,lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index b19d515a18..07de29ab8a 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -134,7 +134,8 @@ ngx_http_lua_socket_udp(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); @@ -197,7 +198,8 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); luaL_checktype(L, 1, LUA_TTABLE); @@ -1494,12 +1496,12 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 78da5a4a78..2db6c551c8 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1511,14 +1511,14 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } /* rc == NGX_ERROR || rc >= NGX_OK */ if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c new file mode 100644 index 0000000000..d3c5a6106b --- /dev/null +++ b/src/ngx_http_lua_timer.c @@ -0,0 +1,470 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_timer.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_probe.h" + + +typedef struct { + int co_ref; + lua_State *co; + + void **main_conf; + void **srv_conf; + void **loc_conf; + + ngx_http_lua_main_conf_t *lmcf; +} ngx_http_lua_timer_t; + + +static int ngx_http_lua_ngx_timer_at(lua_State *L); +static void ngx_http_lua_timer_handler(ngx_event_t *ev); +static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, + size_t len); + + +void +ngx_http_lua_inject_timer_api(lua_State *L) +{ + lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* ngx.timer. */ + + lua_pushcfunction(L, ngx_http_lua_ngx_timer_at); + lua_setfield(L, -2, "at"); + + lua_setfield(L, -2, "timer"); +} + + +static int +ngx_http_lua_ngx_timer_at(lua_State *L) +{ + int co_ref; + u_char *p; + lua_State *mt; /* the main thread */ + lua_State *co; + ngx_msec_t delay; + ngx_event_t *ev; + ngx_http_request_t *r; + ngx_http_lua_timer_t *timer; +#if 0 + ngx_http_connection_t *hc; +#endif + + ngx_http_lua_main_conf_t *lmcf; +#if 0 + ngx_http_core_main_conf_t *cmcf; +#endif + + if (lua_gettop(L) != 2) { + return luaL_error(L, "expecting 2 arguments but got %d", + lua_gettop(L)); + } + + delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); + + luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, + "Lua function expected"); + + lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_rawget(L, LUA_GLOBALSINDEX); + r = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (r == NULL) { + return luaL_error(L, "no request"); + } + + if (ngx_exiting) { + lua_pushnil(L); + lua_pushliteral(L, "process exiting"); + return 2; + } + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + if (lmcf->pending_timers >= lmcf->max_pending_timers) { + lua_pushnil(L); + lua_pushliteral(L, "too many pending timers"); + return 2; + } + + mt = lmcf->lua; + + co = lua_newthread(mt); + + /* stack: time func thread */ + + ngx_http_lua_probe_user_coroutine_create(r, L, co); + + lua_createtable(co, 0, 0); /* the new global table */ + + /* co stack: global_tb */ + + lua_createtable(co, 0, 1); /* the metatable */ + lua_pushvalue(co, LUA_GLOBALSINDEX); + lua_setfield(co, -2, "__index"); + lua_setmetatable(co, -2); + + /* co stack: global_tb */ + + lua_replace(co, LUA_GLOBALSINDEX); + + /* co stack: */ + + dd("stack top: %d", lua_gettop(L)); + + lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ + + /* L stack: time func thread */ + /* mt stack: empty */ + + lua_pushvalue(L, 2); /* copy entry function to top of L*/ + + /* L stack: time func thread func */ + + lua_xmove(L, co, 1); /* move entry function from L to co */ + + /* L stack: time func thread */ + /* co stack: func */ + + lua_pushvalue(co, LUA_GLOBALSINDEX); + lua_setfenv(co, -2); + + /* co stack: thread */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* L stack: time func thread corountines */ + + lua_pushvalue(L, -2); + + /* L stack: time func thread coroutines thread */ + + co_ref = luaL_ref(L, -2); + lua_pop(L, 1); + + /* L stack: time func thread */ + + p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_t), + r->connection->log); + if (p == NULL) { + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, co_ref); + return luaL_error(L, "no memory"); + } + + ev = (ngx_event_t *) p; + + ngx_memzero(ev, sizeof(ngx_event_t)); + + p += sizeof(ngx_event_t); + + timer = (ngx_http_lua_timer_t *) p; + + timer->co_ref = co_ref; + timer->co = co; + timer->main_conf = r->main_conf; + timer->srv_conf = r->srv_conf; + timer->loc_conf = r->loc_conf; + timer->lmcf = lmcf; + + ev->handler = ngx_http_lua_timer_handler; + ev->data = timer; + ev->log = ngx_cycle->log; + + lmcf->pending_timers++; + + ngx_add_timer(ev, delay); + + lua_pushinteger(L, 1); + return 1; +} + + +static void +ngx_http_lua_timer_handler(ngx_event_t *ev) +{ + lua_State *L; + ngx_int_t rc; + ngx_log_t *log; + ngx_connection_t *c = NULL, *saved_c = NULL; + ngx_http_request_t *r = NULL; + ngx_http_lua_ctx_t *ctx; + ngx_http_cleanup_t *cln; + ngx_http_log_ctx_t *logctx; + ngx_http_lua_timer_t timer; + + ngx_http_lua_main_conf_t *lmcf; + ngx_http_core_loc_conf_t *clcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua ngx.timer expired"); + + ngx_memcpy(&timer, ev->data, sizeof(ngx_http_lua_timer_t)); + ngx_free(ev); + ev = NULL; + + lmcf = timer.lmcf; + + lmcf->pending_timers--; + + if (lmcf->running_timers >= lmcf->max_running_timers) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%i lua_max_running_timers are not enough", + lmcf->max_running_timers); + goto abort; + } + + /* create the fake connection (we temporarily use a valid fd (0) to make + ngx_get_connection happy) */ + + if (ngx_cycle->files) { + saved_c = ngx_cycle->files[0]; + } + + c = ngx_get_connection(0, ngx_cycle->log); + + if (ngx_cycle->files) { + ngx_cycle->files[0] = saved_c; + } + + if (c == NULL) { + goto abort; + } + + c->fd = -1; + + c->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); + if (c->pool == NULL) { + goto abort; + } + + log = ngx_pcalloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + goto abort; + } + + logctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); + if (logctx == NULL) { + goto abort; + } + + dd("c pool allocated: %d", (int) (sizeof(ngx_log_t) + + sizeof(ngx_http_log_ctx_t) + sizeof(ngx_http_request_t))); + + logctx->connection = c; + logctx->request = NULL; + logctx->current_request = NULL; + + c->log = log; + c->log->connection = c->number; + c->log->handler = ngx_http_lua_log_timer_error; + c->log->data = logctx; + c->log->action = NULL; + + c->log_error = NGX_ERROR_INFO; + +#if 0 + c->buffer = ngx_create_temp_buf(c->pool, 2); + if (c->buffer == NULL) { + goto abort; + } + + c->buffer->start[0] = CR; + c->buffer->start[1] = LF; +#endif + + /* create the fake request */ + + r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); + if (r == NULL) { + goto abort; + } + + c->requests++; + logctx->request = r; + logctx->current_request = r; + + r->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); + if (r->pool == NULL) { + goto abort; + } + + dd("r pool allocated: %d", (int) (sizeof(ngx_http_lua_ctx_t) + + sizeof(void *) * ngx_http_max_module + sizeof(ngx_http_cleanup_t))); + +#if 0 + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); + if (hc == NULL) { + goto abort; + } + + r->header_in = c->buffer; + r->header_end = c->buffer->start; + + if (ngx_list_init(&r->headers_out.headers, r->pool, 0, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + goto abort; + } + + if (ngx_list_init(&r->headers_in.headers, r->pool, 0, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + goto abort; + } +#endif + + r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); + if (r->ctx == NULL) { + goto abort; + } + +#if 0 + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t)); + if (r->variables == NULL) { + goto abort; + } +#endif + + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + goto abort; + } + + r->headers_in.content_length_n = 0; + c->data = r; +#if 0 + hc->request = r; + r->http_connection = hc; +#endif + r->signature = NGX_HTTP_MODULE; + r->connection = c; + r->main = r; + r->count = 1; + + r->method = NGX_HTTP_UNKNOWN; + + r->headers_in.keep_alive_n = -1; + r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; + r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1; + + r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; + r->discard_body = 1; + + r->main_conf = timer.main_conf; + r->srv_conf = timer.srv_conf; + r->loc_conf = timer.loc_conf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + c->log->file = clcf->error_log->file; + if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + c->log->log_level = clcf->error_log->log_level; + } + + c->error = 1; + + ctx->cur_co_ctx = &ctx->entry_co_ctx; + + L = lmcf->lua; + + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + goto abort; + } + + cln->handler = ngx_http_lua_request_cleanup; + cln->data = r; + ctx->cleanup = &cln->handler; + + ctx->entered_content_phase = 1; + ctx->context = NGX_HTTP_LUA_CONTEXT_TIMER; + + r->read_event_handler = ngx_http_block_reading; + + ctx->cur_co_ctx->co_ref = timer.co_ref; + ctx->cur_co_ctx->co = timer.co; + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + + dd("r connection: %p, log %p", r->connection, r->connection->log); + + /* save the request in coroutine globals table */ + lua_pushvalue(timer.co, LUA_GLOBALSINDEX); + lua_pushlightuserdata(timer.co, &ngx_http_lua_request_key); + lua_pushlightuserdata(timer.co, r); + lua_rawset(timer.co, -3); + lua_pop(timer.co, 1); + /* }}} */ + + lmcf->running_timers++; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + dd("timer lua run thread: %d", (int) rc); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + /* do nothing */ + + } else if (rc == NGX_AGAIN) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); + + } else if (rc == NGX_DONE) { + rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + } else { + rc = NGX_OK; + } + + ngx_http_lua_finalize_request(r, rc); + return; + +abort: + if (timer.co_ref && timer.co) { + lua_pushlightuserdata(timer.co, &ngx_http_lua_coroutines_key); + lua_rawget(timer.co, LUA_REGISTRYINDEX); + luaL_unref(timer.co, -1, timer.co_ref); + lua_settop(timer.co, 0); + } + + if (r && r->pool) { + ngx_destroy_pool(r->pool); + } + + if (c) { + ngx_http_lua_close_fake_connection(c); + } +} + + +static u_char * +ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + return ngx_snprintf(buf, len, ", context: ngx.timer"); +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_timer.h b/src/ngx_http_lua_timer.h new file mode 100644 index 0000000000..0addb18844 --- /dev/null +++ b/src/ngx_http_lua_timer.h @@ -0,0 +1,20 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_TIMER_H_INCLUDED_ +#define _NGX_HTTP_LUA_TIMER_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +void ngx_http_lua_inject_timer_api(lua_State *L); + + +#endif /* _NGX_HTTP_LUA_TIMER_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index c6ad239de5..1b011d77a5 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -47,6 +47,8 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + ngx_http_lua_check_fake_request(L, r); + if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 9d4398f8a1..1132bf6141 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -127,7 +127,8 @@ ngx_http_lua_uthread_wait(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS - | NGX_HTTP_LUA_CONTEXT_CONTENT); + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); coctx = ctx->cur_co_ctx; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 2573860103..701b484595 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -45,6 +45,7 @@ #include "ngx_http_lua_probe.h" #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_contentby.h" +#include "ngx_http_lua_timer.h" #if 1 @@ -93,6 +94,8 @@ static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, static void ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); static ngx_int_t ngx_http_lua_on_abort_resume(ngx_http_request_t *r); +static void ngx_http_lua_close_fake_request(ngx_http_request_t *r); +static void ngx_http_lua_free_fake_request(ngx_http_request_t *r); #ifndef LUA_PATH_SEP @@ -744,7 +747,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - lua_createtable(L, 0 /* narr */, 85 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 86 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); @@ -771,6 +774,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) ngx_http_lua_inject_socket_tcp_api(cf->log, L); ngx_http_lua_inject_socket_udp_api(cf->log, L); ngx_http_lua_inject_uthread_api(cf->log, L); + ngx_http_lua_inject_timer_api(L); ngx_http_lua_inject_misc_api(L); @@ -931,6 +935,13 @@ ngx_http_lua_request_cleanup(void *data) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#if 1 + if (r->connection->fd == -1) { + /* being a fake request */ + lmcf->running_timers--; + } +#endif + L = lmcf->lua; /* we cannot release the ngx.ctx table if we have log_by_lua* hooks @@ -1447,7 +1458,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; done: - if (ctx->entered_content_phase) { + if (ctx->entered_content_phase && r->connection->fd != -1) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* last_buf */); @@ -1494,7 +1505,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) c->timedout = 1; if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); + ngx_http_lua_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); } return NGX_HTTP_REQUEST_TIME_OUT; @@ -1508,7 +1519,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, NGX_ERROR); + ngx_http_lua_finalize_request(r, NGX_ERROR); } return NGX_ERROR; } @@ -1528,7 +1539,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (rc == NGX_ERROR || rc > NGX_OK) { if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); } return rc; @@ -1559,7 +1570,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, NGX_ERROR); + ngx_http_lua_finalize_request(r, NGX_ERROR); } return NGX_ERROR; @@ -2890,14 +2901,14 @@ ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); continue; } /* rc == NGX_ERROR || rc >= NGX_OK */ if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); } return rc; @@ -3150,7 +3161,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if (ctx->on_abort_co_ctx == NULL) { r->connection->error = 1; ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return; } @@ -3163,7 +3174,8 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_lua_finalize_request(r, + NGX_HTTP_INTERNAL_SERVER_ERROR); return; } } @@ -3226,12 +3238,12 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, NGX_DONE); + ngx_http_lua_finalize_request(r, NGX_DONE); return ngx_http_lua_run_posted_threads(c,lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); + ngx_http_lua_finalize_request(r, rc); return NGX_DONE; } @@ -3280,4 +3292,159 @@ ngx_http_lua_test_expect(ngx_http_request_t *r) return NGX_ERROR; } + +void +ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc) +{ + if (r->connection->fd != -1) { + ngx_http_finalize_request(r, rc); + return; + } + + ngx_http_lua_finalize_fake_request(r, rc); +} + + +void +ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_connection_t *c; + + c = r->connection; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http lua finalize fake request: %d, a:%d, c:%d", + rc, r == c->data, r->main->count); + + if (rc == NGX_DONE) { + ngx_http_lua_close_fake_request(r); + return; + } + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ngx_http_lua_close_fake_request(r); + return; + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->write->timer_set) { + c->write->delayed = 0; + ngx_del_timer(c->write); + } + + ngx_http_lua_close_fake_request(r); +} + + +static void +ngx_http_lua_close_fake_request(ngx_http_request_t *r) +{ + ngx_connection_t *c; + + r = r->main; + c = r->connection; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http lua fake request count:%d", r->count); + + if (r->count == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http lua fake request " + "count is zero"); + } + + r->count--; + + if (r->count) { + return; + } + + ngx_http_lua_free_fake_request(r); + ngx_http_lua_close_fake_connection(c); +} + + +static void +ngx_http_lua_free_fake_request(ngx_http_request_t *r) +{ + ngx_log_t *log; + ngx_http_cleanup_t *cln; + ngx_http_log_ctx_t *ctx; + + log = r->connection->log; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http lua close fake " + "request"); + + if (r->pool == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "http lua fake request " + "already closed"); + return; + } + + for (cln = r->cleanup; cln; cln = cln->next) { + if (cln->handler) { + cln->handler(cln->data); + } + } + + /* the various request strings were allocated from r->pool */ + ctx = log->data; + ctx->request = NULL; + + r->request_line.len = 0; + + r->connection->destroyed = 1; + + ngx_destroy_pool(r->pool); +} + + +void +ngx_http_lua_close_fake_connection(ngx_connection_t *c) +{ + ngx_pool_t *pool; + ngx_connection_t *saved_c = NULL; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http lua close fake http connection"); + + c->destroyed = 1; + + pool = c->pool; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + c->read->closed = 1; + c->write->closed = 1; + + /* we temporarily use a valid fd (0) to make ngx_free_connection happy */ + + c->fd = 0; + + if (ngx_cycle->files) { + saved_c = ngx_cycle->files[0]; + } + + ngx_free_connection(c); + + c->fd = -1; + + if (ngx_cycle->files) { + ngx_cycle->files[0] = saved_c; + } + + if (pool) { + ngx_destroy_pool(pool); + } +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 526fa05193..1eb2dd5c5b 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -61,6 +61,7 @@ extern char ngx_http_lua_req_get_headers_metatable_key; : (c) == NGX_HTTP_LUA_CONTEXT_CONTENT ? "content_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_LOG ? "log_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_TIMER ? "ngx.timer" \ : "(unknown)") @@ -71,6 +72,19 @@ extern char ngx_http_lua_req_get_headers_metatable_key; } +#define ngx_http_lua_check_fake_request(L, r) \ + if ((r)->connection->fd == -1) { \ + return luaL_error(L, "API disabled in the current context"); \ + } + + +#define ngx_http_lua_check_fake_request2(L, r, ctx) \ + if ((r)->connection->fd == -1) { \ + return luaL_error(L, "API disabled in the context of %s", \ + ngx_http_lua_context_name((ctx)->context)); \ + } + + lua_State * ngx_http_lua_new_state(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); @@ -150,6 +164,13 @@ ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r); ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev); +void ngx_http_lua_finalize_request(ngx_http_request_t *r, ngx_int_t rc); + +void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, + ngx_int_t rc); + +void ngx_http_lua_close_fake_connection(ngx_connection_t *c); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index 2864ce6519..20f3d103cf 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -69,6 +69,8 @@ ngx_http_lua_var_get(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + #if (NGX_PCRE) if (lua_type(L, -1) == LUA_TNUMBER) { /* it is a regex capturing variable */ @@ -157,6 +159,8 @@ ngx_http_lua_var_set(lua_State *L) return luaL_error(L, "no request object found"); } + ngx_http_lua_check_fake_request(L, r); + /* we skip the first argument that is the table */ /* we read the variable name */ diff --git a/t/062-count.t b/t/062-count.t index 61ba2f8284..bce4e80319 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 85 +ngx: 86 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 85 --- request GET /test --- response_body -85 +86 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 85 +n = 86 --- no_error_log [error] @@ -301,5 +301,25 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 85 +ngx. entry count: 86 + + + +=== TEST 14: entries under ngx.timer +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(ngx.timer) do + n = n + 1 + end + ngx.say("n = ", n) + '; + } +--- request +GET /test +--- response_body +n = 1 +--- no_error_log +[error] diff --git a/t/106-timer.t b/t/106-timer.t new file mode 100644 index 0000000000..b5e7aee779 --- /dev/null +++ b/t/106-timer.t @@ -0,0 +1,2054 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 8 + 67); + +#no_diff(); +no_long_string(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: simple at +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 2: separated global env +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + foo = 3 + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.06) + ngx.say("foo = ", foo) + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer +foo = nil + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 3: lua variable sharing via upvalue +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local foo + local function f() + foo = 3 + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.06) + ngx.say("foo = ", foo) + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer +foo = 3 + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 4: simple at (sleep in the timer callback) +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + ngx.sleep(0.02) + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 5: tcp cosocket in timer handler (short connections) +--- config + server_tokens off; + location = /t { + content_by_lua ' + local begin = ngx.now() + local function fail(...) + ngx.log(ngx.ERR, ...) + end + local function f() + print("my lua timer handler") + local sock = ngx.socket.tcp() + local port = $TEST_NGINX_SERVER_PORT + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok) + + local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + + print("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + if err == "closed" then + break + end + fail("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + print("close: ", ok, " ", err) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } + + location = /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +"connected: 1", +"request sent: 57", +"received: HTTP/1.1 200 OK", +qr/received: Server: \S+/, +"received: Content-Type: text/plain", +"received: Content-Length: 4", +"received: Connection: close", +"received: foo", +"close: nil closed", +] + + + +=== TEST 6: tcp cosocket in timer handler (keep-alive connections) +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 7: 0 timer +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.05 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0(?:[^.]|\.00)/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 8: udp cosocket in timer handler +--- config + location = /t { + content_by_lua ' + local begin = ngx.now() + local function fail(...) + ngx.log(ngx.ERR, ...) + end + local function f() + print("my lua timer handler") + local socket = ngx.socket + -- local socket = require "socket" + + local udp = socket.udp() + + local port = $TEST_NGINX_MEMCACHED_PORT + udp:settimeout(1000) -- 1 sec + + local ok, err = udp:setpeername("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok) + + local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" + local ok, err = udp:send(req) + if not ok then + fail("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + fail("failed to receive data: ", err) + return + end + print("received ", #data, " bytes: ", data) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } + + location = /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +"connected: 1", +"received 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" +] + + + +=== TEST 9: simple at (sleep in the timer callback) - log_by_lua +--- config + location /t { + echo hello world; + log_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + ngx.sleep(0.02) + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello world + +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +qr/\[lua\] \[string "log_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 10: tcp cosocket in timer handler (keep-alive connections) - log_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo hello; + log_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 11: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo hello; + header_filter_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 12: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo hello; + body_filter_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set keep alive: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out_like chop +create 2 in 1 +create 3 in 1 +(?:terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +|terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2)$ + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 13: tcp cosocket in timer handler (keep-alive connections) - set_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + set_by_lua $a ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + return 32 + '; + echo $a; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +32 + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 14: coroutine API +--- config + location /t { + content_by_lua ' + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + local function f() + function f() + local cnt = 0 + for i = 1, 20 do + print("cnt = ", cnt) + cy() + cnt = cnt + 1 + end + end + + local c = cc(f) + for i=1,3 do + cr(c) + print("after resume, i = ", i) + end + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"cnt = 0", +"after resume, i = 1", +"cnt = 1", +"after resume, i = 2", +"cnt = 2", +"after resume, i = 3", +] + + + +=== TEST 15: ngx.thread API +--- config + location /t { + content_by_lua ' + local function fail (...) + ngx.log(ngx.ERR, ...) + end + local function handle() + function f() + print("hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + fail("failed to spawn thread: ", err) + return + end + + print("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + fail("failed to run thread: ", res) + return + end + + print("wait result: ", res) + end + local ok, err = ngx.timer.at(0.01, handle) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +spawn user thread 3 in 2 +terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"hello in thread", +"thread created: zombie", +"wait result: done", +] + + + +=== TEST 16: shared dict +--- http_config + lua_shared_dict dogs 1m; +--- config + location /t { + content_by_lua ' + local function f() + local dogs = ngx.shared.dogs + dogs:set("foo", 32) + dogs:set("bah", 10502) + local val = dogs:get("foo") + print("get foo: ", val, " ", type(val)) + val = dogs:get("bah") + print("get bah: ", val, " ", type(val)) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"get foo: 32 number", +"get bah: 10502 number", +] + + + +=== TEST 17: ngx.exit(0) +--- config + location /t { + content_by_lua ' + local function f() + local function g() + print("BEFORE ngx.exit") + ngx.exit(0) + end + g() + print("CANNOT REACH HERE") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE ngx.exit", +] +--- no_error_log +CANNOT REACH HERE +API disabled + + + +=== TEST 18: ngx.exit(403) +--- config + location /t { + content_by_lua ' + local function f() + local function g() + print("BEFORE ngx.exit") + ngx.exit(403) + end + g() + print("CANNOT REACH HERE") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] +CANNOT REACH HERE +API disabled + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE ngx.exit", +] + + + +=== TEST 19: exit in user thread (entry thread is still pending on ngx.sleep) +--- config + location /t { + content_by_lua ' + local function handle() + local function f() + print("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + print("BEFORE thread spawn") + ngx.thread.spawn(f) + print("AFTER thread spawn") + ngx.sleep(1) + print("entry thread END") + end + local ok, err = ngx.timer.at(0.05, handle) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 1000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 1000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 1000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 1000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_sleep_cleanup) { + println("lua sleep cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +free request +create 3 in 2 +spawn user thread 3 in 2 +add timer 100 +add timer 1000 +expire timer 100 +terminate 3: ok +lua sleep cleanup +delete timer 1000 +delete thread 3 +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] +API disabled +entry thread END + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE thread spawn", +"hello in thread", +"AFTER thread spawn", +] + + + +=== TEST 20: chained timers (0 delay) +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + local ok, err = ngx.timer.at(0, g) + if not ok then + fail("failed to set timer: ", err) + return + end + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 21: chained timers (non-zero delay) +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + local ok, err = ngx.timer.at(0.01, g) + if not ok then + fail("failed to set timer: ", err) + return + end + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 22: multiple parallel timers +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + fail("failed to set timer: ", err) + return + end + local ok, err = ngx.timer.at(0.01, g) + if not ok then + fail("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 23: lua_max_pending_timers +--- http_config + lua_max_pending_timers 1; +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer f: ", err) + return + end + local ok, err = ngx.timer.at(0.01, g) + if not ok then + ngx.say("failed to set timer g: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +failed to set timer g: too many pending timers + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] +[error] + +--- error_log +lua ngx.timer expired +http lua close fake http connection + + + +=== TEST 24: lua_max_pending_timers (just not exceeding) +--- http_config + lua_max_pending_timers 2; +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer f: ", err) + return + end + local ok, err = ngx.timer.at(0.01, g) + if not ok then + ngx.say("failed to set timer g: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] +[error] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 25: lua_max_pending_timers - chained timers (non-zero delay) - not exceeding +--- http_config + lua_max_pending_timers 1; + +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + local ok, err = ngx.timer.at(0.01, g) + if not ok then + fail("failed to set timer: ", err) + return + end + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 26: lua_max_pending_timers - chained timers (zero delay) - not exceeding +--- http_config + lua_max_pending_timers 1; + +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + local ok, err = ngx.timer.at(0, g) + if not ok then + fail("failed to set timer: ", err) + return + end + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + + + +=== TEST 27: lua_max_running_timers (just not enough) +--- http_config + lua_max_running_timers 1; +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local f, g + + g = function () + ngx.sleep(0.01) + end + + f = function () + ngx.sleep(0.01) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer f: ", err) + return + end + local ok, err = ngx.timer.at(0, g) + if not ok then + ngx.say("failed to set timer g: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[crit] +[error] + +--- error_log +1 lua_max_running_timers are not enough +lua ngx.timer expired +http lua close fake http connection + + + +=== TEST 28: lua_max_running_timers (just enough) +--- http_config + lua_max_running_timers 2; +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local f, g + + g = function () + ngx.sleep(0.01) + end + + f = function () + ngx.sleep(0.01) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer f: ", err) + return + end + local ok, err = ngx.timer.at(0, g) + if not ok then + ngx.say("failed to set timer g: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] +[error] + +--- error_log +lua ngx.timer expired +http lua close fake http connection + + + +=== TEST 29: lua_max_running_timers (just enough) - 2 +--- http_config + lua_max_running_timers 2; +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local f, g + + g = function () + ngx.timer.at(0.02, f) + ngx.sleep(0.01) + end + + f = function () + ngx.sleep(0.01) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer f: ", err) + return + end + local ok, err = ngx.timer.at(0, g) + if not ok then + ngx.say("failed to set timer g: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +terminate 1: ok +delete thread 1 +create 4 in 3 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] +[error] + +--- error_log +lua ngx.timer expired +http lua close fake http connection + diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t new file mode 100644 index 0000000000..c51611b956 --- /dev/null +++ b/t/107-timer-errors.t @@ -0,0 +1,1424 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 7); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: accessing nginx variables +--- config + location /t { + content_by_lua ' + local function f() + print("uri: ", ngx.var.uri) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 2: reading ngx.status +--- config + location /t { + content_by_lua ' + local function f() + print("uri: ", ngx.status) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 3: writing ngx.status +--- config + location /t { + content_by_lua ' + local function f() + ngx.status = 200 + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 4: ngx.req.raw_header +--- config + location /t { + content_by_lua ' + local function f() + print("raw header: ", ngx.req.raw_header()) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 5: ngx.req.get_headers +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_headers() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 6: ngx.req.set_header +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_header("Foo", 32) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 7: ngx.req.clear_header +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.clear_header("Foo") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 8: ngx.req.set_uri +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_uri("/foo") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 9: ngx.req.set_uri_args +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_uri_args("foo") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 10: ngx.redirect() +--- config + location /t { + content_by_lua ' + local function f() + ngx.redirect("/foo") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 11: ngx.exec() +--- config + location /t { + content_by_lua ' + local function f() + ngx.exec("/foo") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 12: ngx.say() +--- config + location /t { + content_by_lua ' + local function f() + ngx.say("hello") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 13: ngx.print() +--- config + location /t { + content_by_lua ' + local function f() + ngx.print("hello") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 14: ngx.flush() +--- config + location /t { + content_by_lua ' + local function f() + ngx.flush() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 15: ngx.send_headers() +--- config + location /t { + content_by_lua ' + local function f() + ngx.send_headers() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 16: ngx.req.get_uri_args() +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_uri_args() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 17: ngx.req.read_body +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.read_body() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 18: ngx.req.discard_body +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.discard_body() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 19: ngx.req.init_body +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.init_body() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 20: ngx.header +--- config + location /t { + content_by_lua ' + local function f() + ngx.header.Foo = 3 + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 21: ngx.on_abort +--- config + location /t { + content_by_lua ' + local function f() + ngx.on_abort(f) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 22: ngx.location.capture +--- config + location /t { + content_by_lua ' + local function f() + ngx.location.capture("/") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 23: ngx.location.capture_multi +--- config + location /t { + content_by_lua ' + local function f() + ngx.location.capture_multi{{"/"}} + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 24: ngx.req.get_method +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_method() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 25: ngx.req.set_method +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_method(ngx.HTTP_POST) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 26: ngx.req.http_version +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.http_version() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 27: ngx.req.get_post_args +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_post_args() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 28: ngx.req.get_body_data +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_body_data() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 29: ngx.req.get_body_file +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.get_body_file() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 30: ngx.req.set_body_data +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_body_data("hello") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 31: ngx.req.set_body_file +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.set_body_file("hello") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 32: ngx.req.append_body +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.append_body("hello") + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 33: ngx.req.finish_body +--- config + location /t { + content_by_lua ' + local function f() + ngx.req.finish_body() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 34: ngx.headers_sent +--- config + location /t { + content_by_lua ' + local function f() + ngx.headers_sent() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 35: ngx.eof +--- config + location /t { + content_by_lua ' + local function f() + ngx.eof() + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 36: ngx.req.socket +--- config + location /t { + content_by_lua ' + local function f() + local sock, err = ngx.req.socket() + if not sock then + ngx.log(ngx.ERR, "failed to get req sock: ", err) + end + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t new file mode 100644 index 0000000000..8b4fb553db --- /dev/null +++ b/t/108-timer-safe.t @@ -0,0 +1,1399 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 8 + 60); + +#no_diff(); +no_long_string(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: simple at +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.05) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 2: simple at (sleep in the timer callback) +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + ngx.sleep(0.02) + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.05) + '; + } +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 3: tcp cosocket in timer handler (short connections) +--- config + server_tokens off; + location = /t { + content_by_lua ' + local begin = ngx.now() + local function fail(...) + ngx.log(ngx.ERR, ...) + end + local function f() + print("my lua timer handler") + local sock = ngx.socket.tcp() + local port = $TEST_NGINX_SERVER_PORT + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok) + + local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + + print("request sent: ", bytes) + + while true do + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + if err == "closed" then + break + end + fail("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + print("close: ", ok, " ", err) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.02) + '; + } + + location = /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 eval: $::GCScript +--- stap_out2 +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +"connected: 1", +"request sent: 57", +"received: HTTP/1.1 200 OK", +qr/received: Server: \S+/, +"received: Content-Type: text/plain", +"received: Content-Length: 4", +"received: Connection: close", +"received: foo", +"close: nil closed", +] + + + +=== TEST 4: tcp cosocket in timer handler (keep-alive connections) +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.02) + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 eval: $::GCScript +--- stap_out2 +create 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 5: 0 timer +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f() + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.02 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0(?:[^.]|\.00)/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 6: udp cosocket in timer handler +--- config + location = /t { + content_by_lua ' + local begin = ngx.now() + local function fail(...) + ngx.log(ngx.ERR, ...) + end + local function f() + print("my lua timer handler") + local socket = ngx.socket + -- local socket = require "socket" + + local udp = socket.udp() + + local port = $TEST_NGINX_MEMCACHED_PORT + udp:settimeout(1000) -- 1 sec + + local ok, err = udp:setpeername("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok) + + local req = "\\0\\1\\0\\0\\0\\1\\0\\0flush_all\\r\\n" + local ok, err = udp:send(req) + if not ok then + fail("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + fail("failed to receive data: ", err) + return + end + print("received ", #data, " bytes: ", data) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.05) + '; + } + + location = /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +"connected: 1", +"received 12 bytes: \x{00}\x{01}\x{00}\x{00}\x{00}\x{01}\x{00}\x{00}OK\x{0d}\x{0a}" +] + + + +=== TEST 7: simple at (sleep in the timer callback) - log_by_lua +--- config + location /t { + echo hello world; + echo_sleep 0.07; + log_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + ngx.sleep(0.02) + print("elapsed: ", ngx.now() - begin) + end + local ok, err = ngx.timer.at(0.05, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello world + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +qr/\[lua\] \[string "log_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 8: tcp cosocket in timer handler (keep-alive connections) - log_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo hello; + echo_sleep 0.01; + log_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 9: tcp cosocket in timer handler (keep-alive connections) - header_filter_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo hello; + echo_sleep 0.01; + header_filter_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 10: tcp cosocket in timer handler (keep-alive connections) - body_filter_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + echo_sleep 0.01; + echo hello; + body_filter_by_lua ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + '; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out_like chop +create 2 in 1 +create 3 in 1 +(?:terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +|terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2)$ + +--- response_body +hello + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 11: tcp cosocket in timer handler (keep-alive connections) - set_by_lua +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" + +--- config + location = /t { + set_by_lua $a ' + local begin = ngx.now() + local function f() + print("my lua timer handler") + + local test = require "test" + local port = $TEST_NGINX_MEMCACHED_PORT + test.go(port) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.log(ngx.ERR, "failed to set timer: ", err) + return + end + print("registered timer") + return 32 + '; + echo $a; + echo_sleep 0.01; + } + +--- user_files +>>> test.lua +module("test", package.seeall) + +local function fail(...) + ngx.log(ngx.ERR, ...) +end + +function go(port) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + fail("failed to connect: ", err) + return + end + + print("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + fail("failed to send request: ", err) + return + end + print("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + print("received: ", line) + + else + fail("failed to receive a line: ", err, " [", part, "]") + end + + local ok, err = sock:setkeepalive() + if not ok then + fail("failed to set reusable: ", err) + end +end + +--- request +GET /t +--- stap2 eval: $::StapScript +--- stap3 +global count = 0 +F(ngx_http_lua_header_filter) { + if (count++ == 10) { + println("header filter") + print_ubacktrace() + } +} + +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 + +--- response_body +32 + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"registered timer", +qr/\[lua\] .*? my lua timer handler/, +"lua ngx.timer expired", +"http lua close fake http connection", +qr/go\(\): connected: 1, reused: \d+/, +"go(): request sent: 11", +"go(): received: OK", +] + + + +=== TEST 12: coroutine API +--- config + location /t { + content_by_lua ' + local cc, cr, cy = coroutine.create, coroutine.resume, coroutine.yield + local function f() + function f() + local cnt = 0 + for i = 1, 20 do + print("cnt = ", cnt) + cy() + cnt = cnt + 1 + end + end + + local c = cc(f) + for i=1,3 do + cr(c) + print("after resume, i = ", i) + end + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.01) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"cnt = 0", +"after resume, i = 1", +"cnt = 1", +"after resume, i = 2", +"cnt = 2", +"after resume, i = 3", +] + + + +=== TEST 13: ngx.thread API +--- config + location /t { + content_by_lua ' + local function fail (...) + ngx.log(ngx.ERR, ...) + end + local function handle() + function f() + print("hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + fail("failed to spawn thread: ", err) + return + end + + print("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + fail("failed to run thread: ", res) + return + end + + print("wait result: ", res) + end + local ok, err = ngx.timer.at(0.01, handle) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.02) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +spawn user thread 3 in 2 +terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"hello in thread", +"thread created: zombie", +"wait result: done", +] + + + +=== TEST 14: shared dict +--- http_config + lua_shared_dict dogs 1m; +--- config + location /t { + content_by_lua ' + local function f() + local dogs = ngx.shared.dogs + dogs:set("foo", 32) + dogs:set("bah", 10502) + local val = dogs:get("foo") + print("get foo: ", val, " ", type(val)) + val = dogs:get("bah") + print("get bah: ", val, " ", type(val)) + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.02) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"get foo: 32 number", +"get bah: 10502 number", +] + + + +=== TEST 15: ngx.exit(0) +--- config + location /t { + content_by_lua ' + local function f() + local function g() + print("BEFORE ngx.exit") + ngx.exit(0) + end + g() + print("CANNOT REACH HERE") + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.01) + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[alert] +[crit] + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE ngx.exit", +] +--- no_error_log +CANNOT REACH HERE +API disabled + + + +=== TEST 16: ngx.exit(403) +--- config + location /t { + content_by_lua ' + local function f() + local function g() + print("BEFORE ngx.exit") + ngx.exit(403) + end + g() + print("CANNOT REACH HERE") + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.01) + '; + } +--- request +GET /t +--- stap2 +F(ngx_http_lua_timer_handler) { + println("lua timer handler") +} + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] +CANNOT REACH HERE +API disabled + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE ngx.exit", +] + + + +=== TEST 17: exit in user thread (entry thread is still pending on ngx.sleep) +--- config + location /t { + content_by_lua ' + local function handle() + local function f() + print("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + print("BEFORE thread spawn") + ngx.thread.spawn(f) + print("AFTER thread spawn") + ngx.sleep(1) + print("entry thread END") + end + local ok, err = ngx.timer.at(0.01, handle) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.12) + '; + } +--- request +GET /t +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 1000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 1000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 1000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 1000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_sleep_cleanup) { + println("lua sleep cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create 3 in 2 +spawn user thread 3 in 2 +add timer 100 +add timer 1000 +expire timer 100 +terminate 3: ok +lua sleep cleanup +delete timer 1000 +delete thread 3 +delete thread 2 +terminate 1: ok +delete thread 1 +free request + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] +API disabled +entry thread END + +--- error_log eval +[ +"lua ngx.timer expired", +"http lua close fake http connection", +"BEFORE thread spawn", +"hello in thread", +"AFTER thread spawn", +] + + + +=== TEST 18: chained timers (non-zero delay) +--- config + location /t { + content_by_lua ' + local s = "" + + local function fail(...) + ngx.log(ngx.ERR, ...) + end + + local function g() + s = s .. "[g]" + print("trace: ", s) + end + + local function f() + local ok, err = ngx.timer.at(0.01, g) + if not ok then + fail("failed to set timer: ", err) + return + end + s = s .. "[f]" + end + local ok, err = ngx.timer.at(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + s = "[m]" + ngx.sleep(0.03) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 1: ok +delete thread 1 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] + +--- error_log +lua ngx.timer expired +http lua close fake http connection +trace: [m][f][g] + diff --git a/t/StapThread.pm b/t/StapThread.pm index dd433d3ba7..ce3a9aa75c 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -260,10 +260,12 @@ F(ngx_http_lua_del_all_threads) { println("del all threads") } +/* M(http-lua-info) { msg = user_string($arg1) printf("lua info: %s\n", msg) } +*/ M(http-lua-user-thread-wait) { p = gen_id($arg1) From 40bc1bb0f4ef191e285b066a2a0c682dbf1c9ae6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Apr 2013 11:54:36 -0700 Subject: [PATCH 0056/1981] tests: ensure that TEST_NGINX_USE_STAP is unset when TEST_NGINX_USE_HUP is set. --- t/078-hup-vars.t | 1 + t/080-hup-shdict.t | 1 + 2 files changed, 2 insertions(+) diff --git a/t/078-hup-vars.t b/t/078-hup-vars.t index e9ab8cd358..8aad5cddf9 100644 --- a/t/078-hup-vars.t +++ b/t/078-hup-vars.t @@ -8,6 +8,7 @@ BEGIN { } else { $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; } } diff --git a/t/080-hup-shdict.t b/t/080-hup-shdict.t index a94e096288..5aa142a772 100644 --- a/t/080-hup-shdict.t +++ b/t/080-hup-shdict.t @@ -8,6 +8,7 @@ BEGIN { } else { $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; } } From 8dc910197c7261235d2344ee2ecccad1cc416799 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Apr 2013 20:41:02 -0700 Subject: [PATCH 0057/1981] tests: made two systemtap-based test cases less possible to fail in slow testing mode. --- t/023-rewrite/on-abort.t | 1 + t/024-access/on-abort.t | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 3b04459608..29eb0a8f3b 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -111,6 +111,7 @@ lua req cleanup delete thread 2 delete thread 1 +--- wait: 0.1 --- timeout: 0.2 --- abort --- ignore_response diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 46e4096ba5..134ba10f5b 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -303,7 +303,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.5 +--- wait: 0.6 --- ignore_response --- error_log client prematurely closed connection From 74617ac4c9e784021f4ff5c89f731872a3d0bce1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Apr 2013 11:25:30 -0700 Subject: [PATCH 0058/1981] bugfix: the debug log message "lua set uri jump to " generated by ngx.req.set_uri(uri, true) was wrong for was the old URI. --- src/ngx_http_lua_uri.c | 16 ++++++++-------- t/030-uri-args.t | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index c6ad239de5..7e2865c7c1 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -47,6 +47,12 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + p = (u_char *) luaL_checklstring(L, 1, &len); + + if (len == 0) { + return luaL_error(L, "attempt to use zero-length uri"); + } + if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); @@ -66,19 +72,13 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua set uri jump to \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua set uri jump to \"%*s\"", len, p); ngx_http_lua_check_if_abortable(L, ctx); } } - p = (u_char *) luaL_checklstring(L, 1, &len); - - if (len == 0) { - return luaL_error(L, "attempt to use zero-length uri"); - } - r->uri.data = ngx_palloc(r->pool, len); if (r->uri.data == NULL) { return luaL_error(L, "out of memory"); diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 4595e1f404..e0b8c1e24b 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -10,7 +10,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 8); no_root_location(); @@ -363,6 +363,9 @@ done GET /foo?world --- response_body hello +--- error_log +lua set uri jump to "/bar" +--- log_level: debug From e9f9fdd3afe087b3ce87c2351b1d108f39927721 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Apr 2013 11:49:23 -0700 Subject: [PATCH 0059/1981] bugfix: request hung when rewrite cycled in ngx.req.set_uri(uri, true) instead of throwing out an error log message and a 500 page properly. thanks Calin Don for the report. --- src/ngx_http_lua_util.c | 1 + t/030-uri-args.t | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 2573860103..85a00def76 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2405,6 +2405,7 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, } ngx_http_lua_request_cleanup(r); + ngx_http_lua_init_ctx(ctx); return NGX_OK; } diff --git a/t/030-uri-args.t b/t/030-uri-args.t index e0b8c1e24b..1b9073e8d6 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -10,7 +10,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 11); no_root_location(); @@ -1192,3 +1192,35 @@ arg1: 1356514698 --- no_error_log [error] + + +=== TEST 50: recursive rewrite +--- config + rewrite_by_lua ' + local args = ngx.var.args + if args == "jump" then + ngx.req.set_uri("/jump",true) + end + '; + + location /jump { + echo "Jump around!"; + } + + location / { + echo "$scheme://$http_host$request_uri"; + } +--- request +GET /?jump + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 + +--- no_error_log +[alert] +[crit] +--- error_log +rewrite or internal redirection cycle while processing "/jump" +--- timeout: 10 +--- log_level: debug + From b408d5be9d8942602fec7228674a93f5226c6d6a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Apr 2013 18:36:08 -0700 Subject: [PATCH 0060/1981] feature: ngx.location.capture and ngx.location.capture_multi now return a lua table with the boolean field "truncated", which indicates whether the subrequest response body is truncated. bugfix: we no longer override the subrequest response status code later when error happens. --- src/ngx_http_lua_capturefilter.c | 9 +- src/ngx_http_lua_common.h | 8 + src/ngx_http_lua_subrequest.c | 45 +++- src/ngx_http_lua_util.c | 7 +- src/ngx_http_lua_util.h | 3 +- t/020-subrequest.t | 444 +++++++++++++++++++++++++++++-- 6 files changed, 483 insertions(+), 33 deletions(-) diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index a837fb8e08..9a945ff80d 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -108,6 +108,7 @@ static ngx_int_t ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; + ngx_int_t eof; ngx_http_lua_ctx_t *ctx; ngx_http_lua_ctx_t *pr_ctx; @@ -150,11 +151,17 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in) "lua capture body filter capturing response body, uri " "\"%V\"", &r->uri); - rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->last_body, in); + rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->last_body, in, &eof); if (rc != NGX_OK) { return NGX_ERROR; } + dd("add copy chain eof: %d, sr: %d", (int) eof, r != r->main); + + if (eof) { + ctx->seen_last_for_subreq = 1; + } + ngx_http_lua_discard_bufs(r->pool, in); return NGX_OK; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index f9192b7a03..8e44259f4d 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -221,6 +221,11 @@ struct ngx_http_lua_posted_thread_s { }; +enum { + NGX_HTTP_LUA_SUBREQ_TRUNCATED = 1 +}; + + struct ngx_http_lua_co_ctx_s { void *data; /* user state for cosockets */ @@ -240,6 +245,8 @@ struct ngx_http_lua_co_ctx_s { ngx_str_t *sr_bodies; /* all captured subrequest bodies */ + uint8_t *sr_flags; + unsigned pending_subreqs; /* number of subrequests being waited */ @@ -367,6 +374,7 @@ typedef struct ngx_http_lua_ctx_s { and etc */ unsigned seen_last_in_filter:1; /* used by body_filter_by_lua* */ + unsigned seen_last_for_subreq:1; /* used by body capture filter */ } ngx_http_lua_ctx_t; diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 78da5a4a78..5b1fdee459 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -122,6 +122,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; + size_t sr_flags_len; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; @@ -169,9 +170,10 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); + sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + - sr_bodies_len); + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "out of memory"); @@ -184,6 +186,9 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) p += sr_headers_len; coctx->sr_bodies = (void *) p; + p += sr_bodies_len; + + coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; @@ -924,22 +929,25 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("uri: %.*s", (int) r->uri.len, r->uri.data); /* capture subrequest response status */ - if (rc == NGX_ERROR) { - pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_INTERNAL_SERVER_ERROR; - } else if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - pr_coctx->sr_statuses[ctx->index] = rc; + pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; - } else { - pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; - } + if (pr_coctx->sr_statuses[ctx->index] == 0) { + if (rc == NGX_OK) { + rc = NGX_HTTP_OK; + } + + if (rc == NGX_ERROR) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE) { - pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + pr_coctx->sr_statuses[ctx->index] = rc; + } } - if (pr_coctx->sr_statuses[ctx->index] == 0) { - pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_OK; + if (!ctx->seen_last_for_subreq) { + pr_coctx->sr_flags[ctx->index] |= NGX_HTTP_LUA_SUBREQ_TRUNCATED; } dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); @@ -1175,6 +1183,18 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, lua_pushinteger(co, coctx->sr_statuses[index]); lua_setfield(co, -2, "status"); + dd("captured subrequest flags: %d", (int) coctx->sr_flags[index]); + + /* set truncated flag if truncation happens */ + if (coctx->sr_flags[index] & NGX_HTTP_LUA_SUBREQ_TRUNCATED) { + lua_pushboolean(co, 1); + lua_setfield(co, -2, "truncated"); + + } else { + lua_pushboolean(co, 0); + lua_setfield(co, -2, "truncated"); + } + /* copy captured body */ body_str = &coctx->sr_bodies[index]; @@ -1497,6 +1517,7 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) coctx->sr_statuses = NULL; coctx->sr_headers = NULL; coctx->sr_bodies = NULL; + coctx->sr_flags = NULL; #endif c = r->connection; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 85a00def76..db3a1d3c7a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -800,18 +800,23 @@ ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in) ngx_int_t ngx_http_lua_add_copy_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, - ngx_chain_t ***plast, ngx_chain_t *in) + ngx_chain_t ***plast, ngx_chain_t *in, ngx_int_t *eof) { ngx_chain_t *cl; size_t len; ngx_buf_t *b; len = 0; + *eof = 0; for (cl = in; cl; cl = cl->next) { if (ngx_buf_in_memory(cl->buf)) { len += cl->buf->last - cl->buf->pos; } + + if (cl->buf->last_in_chain || cl->buf->last_buf) { + *eof = 1; + } } if (len == 0) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 526fa05193..a2a5d34969 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -88,7 +88,8 @@ ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r, void ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in); ngx_int_t ngx_http_lua_add_copy_chain(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in); + ngx_http_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in, + ngx_int_t *eof); void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx); diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 669d68783d..55e00d8a0c 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 11); +plan tests => repeat_each() * (blocks() * 3 + 18); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -1239,6 +1239,7 @@ F(ngx_http_finalize_request) { res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1248,6 +1249,16 @@ GET /main --- 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", @@ -1270,12 +1281,13 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=502 -post subreq: rc=0, status=502 +upstream fin req: error=0 eof=1 rc=-1 +post subreq: rc=-1, status=200 --- response_body -status: 502 +status: 200 body: hello world +truncated: true --- no_error_log [error] @@ -1297,6 +1309,7 @@ body: hello world res = ngx.location.capture("/memc") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1306,6 +1319,16 @@ GET /main --- 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", @@ -1330,11 +1353,12 @@ F(ngx_http_finalize_request) { --- stap_out conn err: 110: upstream timed out upstream fin req: error=0 eof=0 rc=504 -post subreq: rc=0, status=504 +post subreq: rc=504, status=200 --- response_body_like chop -^status: 504 -body: +^status: 200 +body: [^\n]* +truncated: true --- error_log upstream timed out @@ -1358,6 +1382,7 @@ upstream timed out res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1389,12 +1414,14 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=502 -post subreq: rc=0, status=502 +upstream fin req: error=0 eof=1 rc=-1 +post subreq: rc=-1, status=200 --- response_body -status: 502 +status: 200 body: hello world +truncated: true + --- no_error_log [error] @@ -1415,6 +1442,7 @@ body: hello world res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1447,12 +1475,14 @@ F(ngx_http_finalize_request) { */ --- stap_out conn err: 110: upstream timed out -upstream fin req: error=0 eof=0 rc=502 -post subreq: rc=0, status=502 +upstream fin req: error=0 eof=0 rc=-1 +post subreq: rc=-1, status=200 --- response_body -status: 502 +status: 200 body: +truncated: true + --- error_log upstream timed out @@ -1474,6 +1504,7 @@ upstream timed out res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1511,6 +1542,8 @@ post subreq: rc=0, status=200 --- response_body status: 200 body: hello world +truncated: false + --- no_error_log [error] @@ -1531,6 +1564,7 @@ body: hello world res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1563,12 +1597,14 @@ F(ngx_http_finalize_request) { */ --- stap_out conn err: 110: upstream timed out -upstream fin req: error=0 eof=0 rc=502 -post subreq: rc=0, status=502 +upstream fin req: error=0 eof=0 rc=-1 +post subreq: rc=-1, status=200 --- response_body -status: 502 +status: 200 body: +truncated: true + --- error_log upstream timed out @@ -1591,6 +1627,7 @@ upstream timed out res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1628,6 +1665,8 @@ post subreq: rc=0, status=200 --- response_body status: 200 body: hello world +truncated: false + --- no_error_log [error] @@ -1648,6 +1687,7 @@ body: hello world res = ngx.location.capture("/proxy") ngx.say("status: ", res.status) ngx.say("body: ", res.body) + ngx.say("truncated: ", res.truncated) '; } --- request @@ -1681,11 +1721,13 @@ F(ngx_http_finalize_request) { --- stap_out conn err: 110: upstream timed out upstream fin req: error=0 eof=0 rc=504 -post subreq: rc=0, status=504 +post subreq: rc=504, status=200 --- response_body -status: 504 +status: 200 body: hello world +truncated: true + --- error_log upstream timed out @@ -1851,3 +1893,369 @@ F(ngx_pool_run_cleanup_file) { --- 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=-1 +post subreq: rc=-1, status=200 + +--- response_body +status: 200 +body: hello world +truncated: true + +--- no_error_log +[error] + + + +=== 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=-1 +post subreq: rc=-1, status=200 + +--- response_body +status: 200 +body: hello world +truncated: true + +--- no_error_log +[error] + + + +=== 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=-1 +post subreq: rc=-1, 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=-1 +post subreq: rc=-1, status=200 + +--- response_body +status: 200 +body: hello world +truncated: true + +--- no_error_log +[error] + From 9e3b32f90cde1e2b7265298082e3003ee63f83e8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Apr 2013 18:57:25 -0700 Subject: [PATCH 0061/1981] fixed a test case that might fail in slow testing modes. --- t/101-on-abort.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 4d60acb053..819539fc98 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -758,6 +758,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- wait: 0.1 --- abort --- ignore_response --- no_error_log From 4eeb47626cae2cf3744fe7f8018bc50951976aaa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 6 Apr 2013 13:08:19 -0700 Subject: [PATCH 0062/1981] removed too short proxy read timeout settings in two cases that are expected to pass. --- t/020-subrequest.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 55e00d8a0c..727a7a18ca 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -2088,7 +2088,7 @@ upstream timed out location /proxy { internal; - proxy_read_timeout 100ms; + #proxy_read_timeout 100ms; proxy_buffering on; proxy_http_version 1.1; proxy_pass http://127.0.0.1:19113; @@ -2146,7 +2146,7 @@ truncated: false location /proxy { internal; - proxy_read_timeout 100ms; + #proxy_read_timeout 100ms; proxy_buffering off; proxy_http_version 1.1; proxy_pass http://127.0.0.1:19113; From 59fe204e928e60f540b7de6aaa7a67ab88e43dff Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 6 Apr 2013 13:12:05 -0700 Subject: [PATCH 0063/1981] added error log checks in 000--init.t. --- t/000--init.t | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/t/000--init.t b/t/000--init.t index 1b2888dabf..d6b009e18d 100644 --- a/t/000--init.t +++ b/t/000--init.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(1); -plan tests => repeat_each() * (blocks() + 1 * 1); +plan tests => repeat_each() * (blocks() * 2 + 1); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -33,6 +33,8 @@ __DATA__ GET /init --- error_code: 200 --- timeout: 10 +--- no_error_log +[error] @@ -47,6 +49,8 @@ GET /init GET /init --- error_code: 200 --- timeout: 10 +--- no_error_log +[error] @@ -61,6 +65,8 @@ GET /init GET /init --- error_code: 200 --- timeout: 10 +--- no_error_log +[error] @@ -77,3 +83,6 @@ GET /flush "OK\r " --- timeout: 10 +--- no_error_log +[error] + From 7c6484dc20ae1333d3c353b53084aa8f8de327f2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 6 Apr 2013 18:03:53 -0700 Subject: [PATCH 0064/1981] updated tests to reflect recent changes in the upstream_truncation patch for the nginx core. --- t/020-subrequest.t | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 727a7a18ca..cefc9590e8 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1281,7 +1281,7 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=-1 +upstream fin req: error=0 eof=1 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -1353,7 +1353,7 @@ F(ngx_http_finalize_request) { --- stap_out conn err: 110: upstream timed out upstream fin req: error=0 eof=0 rc=504 -post subreq: rc=504, status=200 +post subreq: rc=-1, status=200 --- response_body_like chop ^status: 200 @@ -1414,7 +1414,7 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=-1 +upstream fin req: error=0 eof=1 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -1475,7 +1475,7 @@ F(ngx_http_finalize_request) { */ --- stap_out conn err: 110: upstream timed out -upstream fin req: error=0 eof=0 rc=-1 +upstream fin req: error=0 eof=0 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -1597,7 +1597,7 @@ F(ngx_http_finalize_request) { */ --- stap_out conn err: 110: upstream timed out -upstream fin req: error=0 eof=0 rc=-1 +upstream fin req: error=0 eof=0 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -1721,7 +1721,7 @@ F(ngx_http_finalize_request) { --- stap_out conn err: 110: upstream timed out upstream fin req: error=0 eof=0 rc=504 -post subreq: rc=504, status=200 +post subreq: rc=-1, status=200 --- response_body status: 200 @@ -1945,7 +1945,7 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=-1 +upstream fin req: error=0 eof=1 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -2008,7 +2008,7 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=-1 +upstream fin req: error=0 eof=1 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -2070,7 +2070,7 @@ F(ngx_http_finalize_request) { */ --- stap_out conn err: 110: upstream timed out -upstream fin req: error=0 eof=0 rc=-1 +upstream fin req: error=0 eof=0 rc=502 post subreq: rc=-1, status=200 --- response_body @@ -2248,7 +2248,7 @@ F(ngx_http_finalize_request) { } */ --- stap_out -upstream fin req: error=0 eof=1 rc=-1 +upstream fin req: error=0 eof=1 rc=502 post subreq: rc=-1, status=200 --- response_body From a414691b8e20047dabdea1ee1bebfe48b968160a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 9 Apr 2013 16:59:46 -0700 Subject: [PATCH 0065/1981] updated docs to reflect recent changes. --- README | 13 ++++++++++--- README.markdown | 6 +++++- doc/HttpLuaModule.wiki | 6 +++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/README b/README index d9c967cc1b..6fa14fbbea 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.19 - () released on 27 - March 2013. + This document describes ngx_lua v0.7.20 + () released on 9 + April 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -3046,6 +3046,11 @@ Nginx API for Lua can be particularly useful for streaming output. See ngx.flush for more details. + Please note that both "ngx.print" and ngx.say will always invoke the + whole Nginx output body filter chain, which is an expensive operation. + So be careful when calling either of these two in a tight loop; buffer + the data yourself in Lua and save the calls. + ngx.say syntax: *ngx.say(...)* @@ -3194,6 +3199,8 @@ Nginx API for Lua Behind the scene, this method makes use of the Nginx timers. + Since the 0.7.20 release, The 0 time argument can also be specified. + This method was introduced in the "0.5.0rc30" release. ngx.escape_uri diff --git a/README.markdown b/README.markdown index e1cdecc58b..403f7664ac 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.19](https://github.com/chaoslawful/lua-nginx-module/tags) released on 27 March 2013. +This document describes ngx_lua [v0.7.20](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 April 2013. Synopsis ======== @@ -2828,6 +2828,8 @@ The `ngx.null` constant will yield the `"null"` string output. This is an asynchronous call and will return immediately without waiting for all the data to be written into the system send buffer. To run in synchronous mode, call `ngx.flush(true)` after calling `ngx.print`. This can be particularly useful for streaming output. See [ngx.flush](http://wiki.nginx.org/HttpLuaModule#ngx.flush) for more details. +Please note that both `ngx.print` and [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) will always invoke the whole Nginx output body filter chain, which is an expensive operation. So be careful when calling either of these two in a tight loop; buffer the data yourself in Lua and save the calls. + ngx.say ------- **syntax:** *ngx.say(...)* @@ -2949,6 +2951,8 @@ Sleeps for the specified seconds without blocking. One can specify time resoluti Behind the scene, this method makes use of the Nginx timers. +Since the `0.7.20` release, The `0` time argument can also be specified. + This method was introduced in the `0.5.0rc30` release. ngx.escape_uri diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 49db34f0ec..eccdaa2174 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.19] released on 27 March 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.20] released on 9 April 2013. = Synopsis = @@ -2742,6 +2742,8 @@ The ngx.null constant will yield the "null" string out This is an asynchronous call and will return immediately without waiting for all the data to be written into the system send buffer. To run in synchronous mode, call ngx.flush(true) after calling ngx.print. This can be particularly useful for streaming output. See [[#ngx.flush|ngx.flush]] for more details. +Please note that both ngx.print and [[#ngx.say|ngx.say]] will always invoke the whole Nginx output body filter chain, which is an expensive operation. So be careful when calling either of these two in a tight loop; buffer the data yourself in Lua and save the calls. + == ngx.say == '''syntax:''' ''ngx.say(...)'' @@ -2857,6 +2859,8 @@ Sleeps for the specified seconds without blocking. One can specify time resoluti Behind the scene, this method makes use of the Nginx timers. +Since the 0.7.20 release, The 0 time argument can also be specified. + This method was introduced in the 0.5.0rc30 release. == ngx.escape_uri == From 4e8c4bfcbd333ebedcfe04088b3b2917c5c17268 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 11 Apr 2013 12:48:02 -0700 Subject: [PATCH 0066/1981] bugfix: boolean values in an array table were rejected with the exception "attempt to use boolean as query arg value" while encoding a lua (hash) table as URL arguments. thanks Calin Don for reporting this issue. --- src/ngx_http_lua_util.c | 91 ++++++++++++++++++++--------- t/030-uri-args.t | 126 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 183 insertions(+), 34 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index db3a1d3c7a..4d580d390a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2225,26 +2225,37 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, i = 0; lua_pushnil(L); while (lua_next(L, -2) != 0) { - value = (u_char *) lua_tolstring(L, -1, &value_len); + if (lua_isboolean(L, -1)) { + if (lua_toboolean(L, -1)) { + len += key_len; - if (value == NULL) { - luaL_error(L, "attempt to use %s as query arg value", - luaL_typename(L, -1)); - return; - } + } else { + lua_pop(L, 1); + continue; + } + + } else { + value = (u_char *) lua_tolstring(L, -1, &value_len); + + if (value == NULL) { + luaL_error(L, "attempt to use %s as query arg value", + luaL_typename(L, -1)); + return; + } - total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, - value_len, - NGX_ESCAPE_URI); + total_escape += + 2 * ngx_http_lua_escape_uri(NULL, value, + value_len, + NGX_ESCAPE_URI); - len += key_len + value_len + (sizeof("=") - 1); + len += key_len + value_len + (sizeof("=") - 1); + } if (i++ > 0) { total_escape += key_escape; } n++; - lua_pop(L, 1); } @@ -2287,7 +2298,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI); } else { dd("shortcut: no escape required"); @@ -2301,7 +2312,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI); } else { p = ngx_copy(p, value, value_len); @@ -2320,7 +2331,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (lua_toboolean(L, -1)) { if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI); } else { dd("shortcut: no escape required"); @@ -2343,26 +2354,51 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, lua_pushnil(L); while (lua_next(L, -2) != 0) { - if (total_escape) { - p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + if (lua_isboolean(L, -1)) { + if (lua_toboolean(L, -1)) { + if (total_escape) { + p = (u_char *) ngx_http_lua_escape_uri(p, key, + key_len, + NGX_ESCAPE_URI); + + } else { + dd("shortcut: no escape required"); + + p = ngx_copy(p, key, key_len); + } + + } else { + lua_pop(L, 1); + continue; + } } else { - dd("shortcut: no escape required"); - p = ngx_copy(p, key, key_len); - } + if (total_escape) { + p = (u_char *) + ngx_http_lua_escape_uri(p, key, + key_len, + NGX_ESCAPE_URI); - *p++ = '='; + } else { + dd("shortcut: no escape required"); - value = (u_char *) lua_tolstring(L, -1, &value_len); + p = ngx_copy(p, key, key_len); + } - if (total_escape) { - p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + *p++ = '='; - } else { - p = ngx_copy(p, value, value_len); + value = (u_char *) lua_tolstring(L, -1, &value_len); + + if (total_escape) { + p = (u_char *) + ngx_http_lua_escape_uri(p, value, + value_len, + NGX_ESCAPE_URI); + + } else { + p = ngx_copy(p, value, value_len); + } } if (i != n - 1) { @@ -2371,7 +2407,6 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, } i++; - lua_pop(L, 1); } diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 1b9073e8d6..f74980824e 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -10,7 +10,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 11); +plan tests => repeat_each() * (blocks() * 2 + 16); no_root_location(); @@ -684,19 +684,21 @@ args: foo=3 -=== TEST 30: ngx.encode_args (bad table value) +=== TEST 30: boolean values in ngx.encode_args --- config location /lua { - content_by_lua ' + set_by_lua $args_str ' local t = {bar = {32, true}, foo = 3} - rc, err = pcall(ngx.encode_args, t) - ngx.say("rc: ", rc, ", err: ", err) + return ngx.encode_args(t) '; + echo $args_str; } --- request GET /lua --- response_body -rc: false, err: attempt to use boolean as query arg value +foo=3&bar=32&bar +--- no_error_log +[error] @@ -1224,3 +1226,115 @@ rewrite or internal redirection cycle while processing "/jump" --- timeout: 10 --- log_level: debug + + +=== TEST 51: boolean values in ngx.encode_args (trailing arg) +--- config + location /lua { + set_by_lua $args_str ' + local t = {a = {32, true}, foo = 3, bar = 5} + return ngx.encode_args(t) + '; + echo $args_str; + } +--- request +GET /lua +--- response_body +foo=3&a=32&a&bar=5 +--- no_error_log +[error] + + + +=== TEST 52: false boolean values in ngx.encode_args +--- config + location /lua { + set_by_lua $args_str ' + local t = {a = {32, false}, foo = 3, bar = 5} + return ngx.encode_args(t) + '; + echo $args_str; + } +--- request +GET /lua +--- response_body +foo=3&a=32&bar=5 +--- no_error_log +[error] + + + +=== TEST 53: false boolean values in ngx.encode_args (escaping) +--- config + location /lua { + set_by_lua $args_str ' + local t = {["a b"] = {32, false}, foo = 3, bar = 5} + return ngx.encode_args(t) + '; + echo $args_str; + } +--- request +GET /lua +--- response_body +foo=3&a%20b=32&bar=5 +--- no_error_log +[error] + + + +=== TEST 54: true boolean values in ngx.encode_args (escaping) +--- config + location /lua { + set_by_lua $args_str ' + local t = {["a b"] = {32, true}, foo = 3, bar = 5} + return ngx.encode_args(t) + '; + echo $args_str; + } +--- request +GET /lua +--- response_body +foo=3&a%20b=32&a%20b&bar=5 +--- no_error_log +[error] + + + +=== TEST 55: rewrite uri and args (boolean in multi-value args) +--- config + location /bar { + echo $server_protocol $query_string; + } + location /foo { + #rewrite ^ /bar?hello? break; + rewrite_by_lua ' + ngx.req.set_uri_args({a = 3, b = {5, true, 6}}) + ngx.req.set_uri("/bar") + '; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- request + GET /foo?world +--- response_body +HTTP/1.0 a=3&b=5&b&b=6 + + + +=== TEST 56: rewrite uri and args (boolean value) +--- config + location /bar { + echo $server_protocol $query_string; + } + location /foo { + #rewrite ^ /bar?hello? break; + rewrite_by_lua ' + ngx.req.set_uri_args({a = 3, b = true}) + ngx.req.set_uri("/bar") + '; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT; + } +--- request + GET /foo?world +--- response_body +HTTP/1.0 a=3&b + From 069f07541de5df9a79d7ae912f41c75546749253 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 11 Apr 2013 23:59:10 -0700 Subject: [PATCH 0067/1981] feature: when the nginx worker process is quitting (as in server shutdown or HUP reload), all the pending ngx.timer timers expire immediately and their Lua callbacks get called with a true value as the first argument (to indicate whether it is a premature expiration or not). --- .gitignore | 1 + src/ngx_http_lua_common.h | 44 ++++---- src/ngx_http_lua_module.c | 1 + src/ngx_http_lua_timer.c | 229 +++++++++++++++++++++++++++++++++----- t/106-timer.t | 9 +- t/109-timer-hup.t | 160 ++++++++++++++++++++++++++ 6 files changed, 390 insertions(+), 54 deletions(-) create mode 100644 t/109-timer-hup.t diff --git a/.gitignore b/.gitignore index aae0b97fab..ade14fd480 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,4 @@ Makefile tsubreq tthread addr2line +hup diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index bb78734ef2..4c3b08352d 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -94,42 +94,44 @@ typedef struct { struct ngx_http_lua_main_conf_s { - lua_State *lua; + lua_State *lua; - ngx_str_t lua_path; - ngx_str_t lua_cpath; + ngx_str_t lua_path; + ngx_str_t lua_cpath; - ngx_pool_t *pool; + ngx_pool_t *pool; - ngx_int_t max_pending_timers; - ngx_int_t pending_timers; + ngx_int_t max_pending_timers; + ngx_int_t pending_timers; - ngx_int_t max_running_timers; - ngx_int_t running_timers; + ngx_int_t max_running_timers; + ngx_int_t running_timers; + + ngx_connection_t *watcher; /* for watching the process exit event */ #if (NGX_PCRE) - ngx_int_t regex_cache_entries; - ngx_int_t regex_cache_max_entries; + ngx_int_t regex_cache_entries; + ngx_int_t regex_cache_max_entries; #endif - ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ + ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ - ngx_array_t *preload_hooks; /* of ngx_http_lua_preload_hook_t */ + ngx_array_t *preload_hooks; /* of ngx_http_lua_preload_hook_t */ - ngx_flag_t postponed_to_rewrite_phase_end; - ngx_flag_t postponed_to_access_phase_end; + ngx_flag_t postponed_to_rewrite_phase_end; + ngx_flag_t postponed_to_access_phase_end; ngx_http_lua_conf_handler_pt init_handler; ngx_str_t init_src; ngx_uint_t shm_zones_inited; - unsigned requires_header_filter:1; - unsigned requires_body_filter:1; - unsigned requires_capture_filter:1; - unsigned requires_rewrite:1; - unsigned requires_access:1; - unsigned requires_log:1; - unsigned requires_shm:1; + unsigned requires_header_filter:1; + unsigned requires_body_filter:1; + unsigned requires_capture_filter:1; + unsigned requires_rewrite:1; + unsigned requires_access:1; + unsigned requires_log:1; + unsigned requires_shm:1; }; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 4d7ecc1b14..8e412cf4b8 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -505,6 +505,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->lua_cpath = { 0, NULL }; * lmcf->pending_timers = 0; * lmcf->running_timers = 0; + * lmcf->watcher = NULL; * lmcf->regex_cache_entries = 0; * lmcf->shm_zones = NULL; * lmcf->init_handler = NULL; diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index d3c5a6106b..20d563a180 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -17,6 +17,8 @@ typedef struct { + unsigned premature; /* :1 */ + int co_ref; lua_State *co; @@ -25,13 +27,14 @@ typedef struct { void **loc_conf; ngx_http_lua_main_conf_t *lmcf; -} ngx_http_lua_timer_t; +} ngx_http_lua_timer_ctx_t; static int ngx_http_lua_ngx_timer_at(lua_State *L); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char * ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len); +static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev); void @@ -56,11 +59,12 @@ ngx_http_lua_ngx_timer_at(lua_State *L) ngx_msec_t delay; ngx_event_t *ev; ngx_http_request_t *r; - ngx_http_lua_timer_t *timer; + ngx_connection_t *saved_c = NULL; #if 0 ngx_http_connection_t *hc; #endif + ngx_http_lua_timer_ctx_t *tctx; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; @@ -99,6 +103,33 @@ ngx_http_lua_ngx_timer_at(lua_State *L) return 2; } + if (lmcf->watcher == NULL) { + /* create the watcher fake connection */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua creating fake watcher connection"); + + if (ngx_cycle->files) { + saved_c = ngx_cycle->files[0]; + } + + lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); + + if (ngx_cycle->files) { + ngx_cycle->files[0] = saved_c; + } + + if (lmcf->watcher == NULL) { + return luaL_error(L, "no memory"); + } + + lmcf->watcher->fd = -2; /* to work around the -1 check in + ngx_worker_process_cycle */ + lmcf->watcher->idle = 1; + lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; + lmcf->watcher->data = lmcf; + } + mt = lmcf->lua; co = lua_newthread(mt); @@ -157,7 +188,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) /* L stack: time func thread */ - p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_t), + p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); @@ -172,17 +203,18 @@ ngx_http_lua_ngx_timer_at(lua_State *L) p += sizeof(ngx_event_t); - timer = (ngx_http_lua_timer_t *) p; + tctx = (ngx_http_lua_timer_ctx_t *) p; - timer->co_ref = co_ref; - timer->co = co; - timer->main_conf = r->main_conf; - timer->srv_conf = r->srv_conf; - timer->loc_conf = r->loc_conf; - timer->lmcf = lmcf; + tctx->premature = 0; + tctx->co_ref = co_ref; + tctx->co = co; + tctx->main_conf = r->main_conf; + tctx->srv_conf = r->srv_conf; + tctx->loc_conf = r->loc_conf; + tctx->lmcf = lmcf; ev->handler = ngx_http_lua_timer_handler; - ev->data = timer; + ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; @@ -205,19 +237,19 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_log_ctx_t *logctx; - ngx_http_lua_timer_t timer; + ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); - ngx_memcpy(&timer, ev->data, sizeof(ngx_http_lua_timer_t)); + ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t)); ngx_free(ev); ev = NULL; - lmcf = timer.lmcf; + lmcf = tctx.lmcf; lmcf->pending_timers--; @@ -370,9 +402,9 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; r->discard_body = 1; - r->main_conf = timer.main_conf; - r->srv_conf = timer.srv_conf; - r->loc_conf = timer.loc_conf; + r->main_conf = tctx.main_conf; + r->srv_conf = tctx.srv_conf; + r->loc_conf = tctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); c->log->file = clcf->error_log->file; @@ -400,23 +432,25 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) r->read_event_handler = ngx_http_block_reading; - ctx->cur_co_ctx->co_ref = timer.co_ref; - ctx->cur_co_ctx->co = timer.co; + ctx->cur_co_ctx->co_ref = tctx.co_ref; + ctx->cur_co_ctx->co = tctx.co; ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; dd("r connection: %p, log %p", r->connection, r->connection->log); /* save the request in coroutine globals table */ - lua_pushvalue(timer.co, LUA_GLOBALSINDEX); - lua_pushlightuserdata(timer.co, &ngx_http_lua_request_key); - lua_pushlightuserdata(timer.co, r); - lua_rawset(timer.co, -3); - lua_pop(timer.co, 1); + lua_pushvalue(tctx.co, LUA_GLOBALSINDEX); + lua_pushlightuserdata(tctx.co, &ngx_http_lua_request_key); + lua_pushlightuserdata(tctx.co, r); + lua_rawset(tctx.co, -3); + lua_pop(tctx.co, 1); /* }}} */ lmcf->running_timers++; - rc = ngx_http_lua_run_thread(L, r, ctx, 0); + lua_pushboolean(tctx.co, tctx.premature); + + rc = ngx_http_lua_run_thread(L, r, ctx, 1); dd("timer lua run thread: %d", (int) rc); @@ -436,11 +470,11 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) return; abort: - if (timer.co_ref && timer.co) { - lua_pushlightuserdata(timer.co, &ngx_http_lua_coroutines_key); - lua_rawget(timer.co, LUA_REGISTRYINDEX); - luaL_unref(timer.co, -1, timer.co_ref); - lua_settop(timer.co, 0); + if (tctx.co_ref && tctx.co) { + lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); + lua_rawget(tctx.co, LUA_REGISTRYINDEX); + luaL_unref(tctx.co, -1, tctx.co_ref); + lua_settop(tctx.co, 0); } if (r && r->pool) { @@ -467,4 +501,139 @@ ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len) return ngx_snprintf(buf, len, ", context: ngx.timer"); } + +static void +ngx_http_lua_abort_pending_timers(ngx_event_t *ev) +{ + ngx_int_t i, n; + ngx_event_t **events; + ngx_connection_t *c, *saved_c = NULL; + ngx_rbtree_node_t *cur, *prev, *next, *sentinel; + ngx_http_lua_timer_ctx_t *tctx; + ngx_http_lua_main_conf_t *lmcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua abort pending timers HERE"); + + c = ev->data; + lmcf = c->data; + + dd("lua connection fd: %d", (int) c->fd); + + if (!c->close) { + return; + } + + c->read->closed = 1; + c->write->closed = 1; + + /* we temporarily use a valid fd (0) to make ngx_free_connection happy */ + + c->fd = 0; + + if (ngx_cycle->files) { + saved_c = ngx_cycle->files[0]; + } + + ngx_free_connection(c); + + c->fd = -1; + + if (ngx_cycle->files) { + ngx_cycle->files[0] = saved_c; + } + + if (lmcf->pending_timers == 0) { + return; + } + + /* expire pending timers immediately */ + + sentinel = ngx_event_timer_rbtree.sentinel; + + prev = NULL; + cur = ngx_event_timer_rbtree.root; + + events = ngx_pcalloc(ngx_cycle->pool, + lmcf->pending_timers * sizeof(ngx_event_t)); + if (events == NULL) { + return; + } + + n = 0; + + dd("root: %p, root parent: %p, sentinel: %p", cur, cur->parent, sentinel); + + while (lmcf->pending_timers > n) { + if (cur == sentinel || cur == NULL) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "lua pending timer counter got out of sync: %i", + lmcf->pending_timers); + break; + } + + if (prev == cur->parent) { + next = cur->left; + if (next == sentinel) { + ev = (ngx_event_t *) + ((char *) cur - offsetof(ngx_event_t, timer)); + + if (ev->handler == ngx_http_lua_timer_handler) { + dd("found node: %p", cur); + events[n++] = ev; + } + + next = (cur->right != sentinel) ? cur->right : cur->parent; + } + + } else if (prev == cur->left) { + ev = (ngx_event_t *) + ((char *) cur - offsetof(ngx_event_t, timer)); + + if (ev->handler == ngx_http_lua_timer_handler) { + dd("found node 2: %p", cur); + events[n++] = ev; + } + + next = (cur->right != sentinel) ? cur->right : cur->parent; + + } else if (prev == cur->right) { + next = cur->parent; + + } else { + next = NULL; + } + + prev = cur; + cur = next; + } + + for (i = 0; i < n; i++) { + ev = events[i]; + + ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer); + +#if (NGX_DEBUG) + ev->timer.left = NULL; + ev->timer.right = NULL; + ev->timer.parent = NULL; +#endif + + ev->timer_set = 0; + + ev->timedout = 1; + + tctx = ev->data; + tctx->premature = 1; + + ev->handler(ev); + } + + if (lmcf->pending_timers) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "lua pending timer counter got out of sync: %i", + lmcf->pending_timers); + } +} + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/106-timer.t b/t/106-timer.t index b5e7aee779..6f9a6f69f2 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -13,7 +13,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 8 + 67); +plan tests => repeat_each() * (blocks() * 8 + 69); #no_diff(); no_long_string(); @@ -33,8 +33,9 @@ __DATA__ location /t { content_by_lua ' local begin = ngx.now() - local function f() + local function f(premature) print("elapsed: ", ngx.now() - begin) + print("timer prematurely expired: ", premature) end local ok, err = ngx.timer.at(0.05, f) if not ok then @@ -64,12 +65,14 @@ registered timer [error] [alert] [crit] +timer prematurely expired: true --- error_log eval [ qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, "lua ngx.timer expired", -"http lua close fake http connection" +"http lua close fake http connection", +"timer prematurely expired: false", ] diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t new file mode 100644 index 0000000000..4365b04f16 --- /dev/null +++ b/t/109-timer-hup.t @@ -0,0 +1,160 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use lib 'lib'; +use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); + + +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * 33; + +#no_diff(); +no_long_string(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: single timer +--- config + location /t { + content_by_lua ' + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local i = 0 + local function f(premature) + i = i + 1 + print("timer prematurely expired: ", premature) + print("in callback: hello, ", i) + end + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + os.execute("kill -HUP " .. pid) + '; + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +in callback: hello, 2 +timer prematurely expired: false + +--- error_log +lua abort pending timers +lua ngx.timer expired +http lua close fake http connection +in callback: hello, 1 +timer prematurely expired: true + + + +=== TEST 2: multiple timers +--- config + location /t { + content_by_lua ' + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local i = 0 + local function f(premature) + i = i + 1 + print("timer prematurely expired: ", premature) + print("in callback: hello, ", i, "!") + end + for i = 1, 10 do + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + ngx.say("registered timers") + os.execute("kill -HUP " .. pid) + '; + } +--- request +GET /t + +--- response_body +registered timers + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +in callback: hello, 11! +timer prematurely expired: false + +--- error_log +lua abort pending timers +lua ngx.timer expired +http lua close fake http connection +in callback: hello, 1! +in callback: hello, 2! +in callback: hello, 3! +in callback: hello, 4! +in callback: hello, 5! +in callback: hello, 6! +in callback: hello, 7! +in callback: hello, 8! +in callback: hello, 9! +in callback: hello, 10! +timer prematurely expired: true + From 10edc8cb03dc5ed1e2e3572ae327b7e22091ef3b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 12 Apr 2013 12:29:20 -0700 Subject: [PATCH 0068/1981] added a passing test for calling ngx.timer.at() after HUP reload. --- t/109-timer-hup.t | 58 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 4365b04f16..0443c3c35b 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -28,7 +28,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * 33; +plan tests => repeat_each() * 45; #no_diff(); no_long_string(); @@ -158,3 +158,59 @@ in callback: hello, 9! in callback: hello, 10! timer prematurely expired: true + + +=== TEST 3: trying to add new timer after HUP reload +--- config + location /t { + content_by_lua ' + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local function f(premature) + print("timer prematurely expired: ", premature) + local ok, err = ngx.timer.at(0, f) + if not ok then + print("failed to register a new timer after reload: ", err) + else + print("registered a new timer after reload") + end + end + local ok, err = ngx.timer.at(3, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + os.execute("kill -HUP " .. pid) + '; + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.2 +--- no_error_log +[error] +[alert] +[crit] +in callback: hello, 2 +timer prematurely expired: false + +--- error_log +lua abort pending timers +lua ngx.timer expired +http lua close fake http connection +timer prematurely expired: true +failed to register a new timer after reload: process exiting, context: ngx.timer + From 26d679f8d4071b07c9347e7706b7b45a51d90301 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 13 Apr 2013 11:16:35 -0700 Subject: [PATCH 0069/1981] bugfix: ngx.req.raw_header() would return an empty string value when the default header buffer (c->buffer) can hold the request line but not the whole header. thanks KDr2 for reporting this issue in #229. --- src/ngx_http_lua_headers.c | 156 ++++++++++++++++++++++++------------- t/104-req-raw-header.t | 53 +++++++++++++ 2 files changed, 154 insertions(+), 55 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index a7a03a14f9..1c9e39ec59 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -72,7 +72,8 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) size_t size; ngx_buf_t *b, *first = NULL; ngx_int_t i; - ngx_http_request_t *r; + ngx_connection_t *c; + ngx_http_request_t *r, *mr; ngx_http_connection_t *hc; n = lua_gettop(L); @@ -91,18 +92,67 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } - hc = r->main->http_connection; + mr = r->main; + hc = mr->http_connection; + c = mr->connection; + +#if 0 + dd("hc->nbusy: %d", (int) hc->nbusy); + + dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, + hc->busy[0]->last, hc->busy[0]->end); + + dd("request line: %p %p", mr->request_line.data, + mr->request_line.data + mr->request_line.len); + + dd("header in: %p %p %p %p", mr->header_in->start, + mr->header_in->pos, mr->header_in->last, + mr->header_in->end); + + dd("c->buffer: %p %p %p %p", c->buffer->start, + c->buffer->pos, c->buffer->last, + c->buffer->end); +#endif + + size = 0; + b = c->buffer; + + if (mr->request_line.data >= b->start + && mr->request_line.data + mr->request_line.len + 2 <= b->pos) + { + first = b; + + if (mr->header_in == b) { + size += mr->header_end + 2 - mr->request_line.data; + + } else { + /* the subsequent part of the header is in the large header + * buffers */ +#if 1 + p = b->pos; + size += p - mr->request_line.data; + + /* skip truncated header entries (if any) */ + while (b->pos > b->start && b->pos[-1] != LF) { + b->pos--; + size--; + } +#endif + } + } if (hc->nbusy) { - b = NULL; /* to suppress a gcc warning */ - size = 0; + b = NULL; for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; + dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), + b->start); + if (first == NULL) { - if (r->main->request_line.data >= b->pos - || r->main->request_line.data - + r->main->request_line.len + 2 + if (mr->request_line.data >= b->pos + || mr->request_line.data + + mr->request_line.len + 2 <= b->start) { continue; @@ -112,35 +162,53 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) first = b; } - if (b == r->main->header_in) { - size += r->main->header_end + 2 - b->start; + if (b == mr->header_in) { + size += mr->header_end + 2 - b->start; break; } size += b->pos - b->start; } + } - } else { - b = r->main->header_in; + data = lua_newuserdata(L, size); + last = data; - if (b == NULL) { - lua_pushnil(L); - return 1; + b = c->buffer; + if (first == b) { + if (mr->header_in == b) { + pos = mr->header_end + 2; + + } else { + pos = b->pos; } - if (b == r->main->header_in) { - size = r->main->header_end + 2 - r->main->request_line.data; + if (no_req_line) { + last = ngx_copy(data, + mr->request_line.data + + mr->request_line.len + 2, + pos - mr->request_line.data + - mr->request_line.len - 2); } else { - size = b->pos - r->main->request_line.data; + last = ngx_copy(data, mr->request_line.data, + pos - mr->request_line.data); } - } - data = lua_newuserdata(L, size); + for (p = data; p != last; p++) { + if (*p == '\0') { + if (p + 1 != last && *(p + 1) == LF) { + *p = CR; + + } else { + *p = ':'; + } + } + } + } if (hc->nbusy) { - last = data; - found = 0; + found = (b == c->buffer); for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; @@ -155,28 +223,28 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) p = last; - if (b == r->main->header_in) { - pos = r->main->header_end + 2; + if (b == mr->header_in) { + pos = mr->header_end + 2; } else { pos = b->pos; } if (b == first) { - dd("request line: %.*s", (int) r->main->request_line.len, - r->main->request_line.data); + dd("request line: %.*s", (int) mr->request_line.len, + mr->request_line.data); if (no_req_line) { last = ngx_copy(last, - r->main->request_line.data - + r->main->request_line.len + 2, - pos - r->main->request_line.data - - r->main->request_line.len - 2); + mr->request_line.data + + mr->request_line.len + 2, + pos - mr->request_line.data + - mr->request_line.len - 2); } else { last = ngx_copy(last, - r->main->request_line.data, - pos - r->main->request_line.data); + mr->request_line.data, + pos - mr->request_line.data); } @@ -206,36 +274,14 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } } - if (b == r->main->header_in) { + if (b == mr->header_in) { break; } } - - } else { - if (no_req_line) { - last = ngx_copy(data, - r->main->request_line.data - + r->main->request_line.len + 2, - size - r->main->request_line.len - 2); - - } else { - last = ngx_copy(data, r->main->request_line.data, size); - } - - for (p = data; p != last; p++) { - if (*p == '\0') { - if (p + 1 != last && *(p + 1) == LF) { - *p = CR; - - } else { - *p = ':'; - } - } - } } if (last - data > (ssize_t) size) { - return luaL_error(L, "buffer error"); + return luaL_error(L, "buffer error: %d", (int) (last - data - size)); } lua_pushlstring(L, (char *) data, last - data); diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index cf75914851..cc1a145181 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -542,3 +542,56 @@ Connection: Close\r [error] --- timeout: 5 + + +=== TEST 20: raw_header (the default header buffer can hold the request line, but not the header entries) - without request line) +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header(true)) + '; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; +$s .= "Accept: */*\n"; +$s .= "Cookie: " . "C" x 1200 . "\n"; +$s +--- response_body eval +"Host: localhost\r +Connection: Close\r +User-Agent: curl\r +Bah: bah\r +Accept: */*\r +Cookie: " . ("C" x 1200) . "\r\n\r\n" +--- no_error_log +[error] + + + +=== TEST 21: raw_header (the default header buffer can hold the request line, but not the header entries) - with request line) +--- config + location /t { + content_by_lua ' + ngx.print(ngx.req.raw_header()) + '; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; +$s .= "Accept: */*\n"; +$s .= "Cookie: " . "C" x 1200 . "\n"; +$s +--- response_body eval +"GET /t HTTP/1.1\r +Host: localhost\r +Connection: Close\r +User-Agent: curl\r +Bah: bah\r +Accept: */*\r +Cookie: " . ("C" x 1200) . "\r\n\r\n" +--- no_error_log +[error] + From 6717d1153f5676216dcf4544e3ca20e857478577 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 13 Apr 2013 20:03:58 -0700 Subject: [PATCH 0070/1981] feature: added support for user arguments to the user callback function specified in ngx.timer.add(); the user callback function has the prototype "function(premature, user_arg1, user_arg2, ...)". --- src/ngx_http_lua_timer.c | 40 ++++++++++++++++++++---------- t/106-timer.t | 53 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 20d563a180..38e9cd85e0 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -52,7 +52,7 @@ ngx_http_lua_inject_timer_api(lua_State *L) static int ngx_http_lua_ngx_timer_at(lua_State *L) { - int co_ref; + int nargs, co_ref; u_char *p; lua_State *mt; /* the main thread */ lua_State *co; @@ -70,9 +70,10 @@ ngx_http_lua_ngx_timer_at(lua_State *L) ngx_http_core_main_conf_t *cmcf; #endif - if (lua_gettop(L) != 2) { - return luaL_error(L, "expecting 2 arguments but got %d", - lua_gettop(L)); + nargs = lua_gettop(L); + if (nargs < 2) { + return luaL_error(L, "expecting at least 2 arguments but got %d", + nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); @@ -134,7 +135,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) co = lua_newthread(mt); - /* stack: time func thread */ + /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); @@ -157,36 +158,43 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ - /* L stack: time func thread */ + /* L stack: time func [args] thread */ /* mt stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ - /* L stack: time func thread func */ + /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ - /* L stack: time func thread */ + /* L stack: time func [args] thread */ /* co stack: func */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); - /* co stack: thread */ + /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - /* L stack: time func thread corountines */ + /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); - /* L stack: time func thread coroutines thread */ + /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); - /* L stack: time func thread */ + /* L stack: time func [args] thread */ + + if (nargs > 2) { + lua_pop(L, 1); /* L stack: time func [args] */ + lua_xmove(L, co, nargs - 2); /* L stack: time func */ + + /* co stack: func [args] */ + } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); @@ -229,6 +237,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) static void ngx_http_lua_timer_handler(ngx_event_t *ev) { + int n; lua_State *L; ngx_int_t rc; ngx_log_t *log; @@ -450,7 +459,12 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) lua_pushboolean(tctx.co, tctx.premature); - rc = ngx_http_lua_run_thread(L, r, ctx, 1); + n = lua_gettop(tctx.co); + if (n > 2) { + lua_insert(tctx.co, 2); + } + + rc = ngx_http_lua_run_thread(L, r, ctx, n - 1); dd("timer lua run thread: %d", (int) rc); diff --git a/t/106-timer.t b/t/106-timer.t index 6f9a6f69f2..3fcdfda07e 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -13,7 +13,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 8 + 69); +plan tests => repeat_each() * (blocks() * 8 + 73); #no_diff(); no_long_string(); @@ -2055,3 +2055,54 @@ registered timer lua ngx.timer expired http lua close fake http connection + + +=== TEST 30: user args +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f(premature, a, b, c) + print("elapsed: ", ngx.now() - begin) + print("timer prematurely expired: ", premature) + print("timer user args: ", a, " ", b, " ", c) + end + local ok, err = ngx.timer.at(0.05, f, 1, "hello", true) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] +timer prematurely expired: true + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection", +"timer prematurely expired: false", +"timer user args: 1 hello true", +] + From f081f212d33689935d020a30240d72ed5e0e3152 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 16 Apr 2013 16:17:17 -0700 Subject: [PATCH 0071/1981] bumped version to 0.7.21. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 6fa14fbbea..52cecdd3cf 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.20 - () released on 9 + This document describes ngx_lua v0.7.21 + () released on 16 April 2013. Synopsis diff --git a/README.markdown b/README.markdown index 403f7664ac..5e5b0b29cd 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.20](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 April 2013. +This document describes ngx_lua [v0.7.21](https://github.com/chaoslawful/lua-nginx-module/tags) released on 16 April 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index eccdaa2174..16bfec71fb 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.20] released on 9 April 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.21] released on 16 April 2013. = Synopsis = From d43a39c59ee5b64077acf6fcb9021882c4375c5e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 20 Apr 2013 19:35:05 -0700 Subject: [PATCH 0072/1981] bugfix: setting ngx.header.etag could not affect other things reading the ETag response header (like the "etag" directive introduced in nginx 1.3.3+). thanks Brian Akins for the patch in #213. --- src/ngx_http_lua_headers_out.c | 4 ++ t/110-etag.t | 85 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 t/110-etag.t diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index e06ebeeda5..2a43c66984 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -88,6 +88,10 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, etag), ngx_http_set_builtin_header }, + { ngx_string("ETag"), + offsetof(ngx_http_headers_out_t, etag), + ngx_http_set_builtin_header }, + { ngx_string("Content-Length"), offsetof(ngx_http_headers_out_t, content_length), ngx_http_set_content_length_header }, diff --git a/t/110-etag.t b/t/110-etag.t new file mode 100644 index 0000000000..c2fc04c937 --- /dev/null +++ b/t/110-etag.t @@ -0,0 +1,85 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: If-None-Match true +--- config + location /t { + content_by_lua ' + ngx.header["ETag"] = "123456789" + ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" + ngx.say(ngx.var.http_if_none_match) + '; + } +--- request +GET /t +--- more_headers +If-None-Match: 123456789 +If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT +--- response_body +--- error_code: 304 +--- no_error_log +[error] + + + +=== TEST 2: If-None-Match false +--- config + location /t { + etag on; + content_by_lua ' + ngx.header["ETag"] = "123456789" + ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" + ngx.say(ngx.var.http_if_none_match) + '; + } +--- request +GET /t +--- more_headers +If-None-Match: 123456780 +If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT +--- response_body +123456780 +--- no_error_log +[error] +--- skip_nginx: 3: < 1.3.3 + + + +=== TEST 3: Etag clear +--- config + location /t { + etag on; + content_by_lua ' + ngx.header["ETag"] = "123456789" + ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" + ngx.header["ETag"] = nil + ngx.say(ngx.var.http_if_none_match) + '; + } +--- request +GET /t +--- more_headers +If-None-Match: 123456789 +If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT +--- response_body +123456789 +--- no_error_log +[error] +--- skip_nginx: 3: < 1.3.3 + From d997f7401fb27fbb9d8aac2e0c00d5a3bb559b87 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 20 Apr 2013 20:08:51 -0700 Subject: [PATCH 0073/1981] refactor: replaced "ngx_lua_" with "ngx_http_lua_" in the identifiers used in ngx_http_lua_regex.c. --- src/ngx_http_lua_regex.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 41d0701ba1..63f0a1ac59 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -60,7 +60,7 @@ typedef struct { pcre *regex; int captures; ngx_str_t err; -} ngx_lua_regex_compile_t; +} ngx_http_lua_regex_compile_t; typedef struct { @@ -77,7 +77,7 @@ typedef struct { static int ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L); static ngx_uint_t ngx_http_lua_ngx_re_parse_opts(lua_State *L, - ngx_lua_regex_compile_t *re, ngx_str_t *opts, int narg); + ngx_http_lua_regex_compile_t *re, ngx_str_t *opts, int narg); static int ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global); static int ngx_http_lua_ngx_re_match(lua_State *L); static int ngx_http_lua_ngx_re_gmatch(lua_State *L); @@ -85,7 +85,7 @@ static int ngx_http_lua_ngx_re_sub(lua_State *L); static int ngx_http_lua_ngx_re_gsub(lua_State *L); static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd); -static ngx_int_t ngx_lua_regex_compile(ngx_lua_regex_compile_t *rc); +static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc); static void ngx_http_lua_ngx_re_gmatch_cleanup(void *data); static int ngx_http_lua_ngx_re_gmatch_gc(lua_State *L); static void ngx_http_lua_re_collect_named_captures(lua_State *L, @@ -112,7 +112,6 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_str_t subj; ngx_str_t pat; ngx_str_t opts; - ngx_lua_regex_compile_t re_comp; ngx_http_lua_regex_t *re; const char *msg; ngx_int_t rc; @@ -130,6 +129,8 @@ ngx_http_lua_ngx_re_match(lua_State *L) int name_entry_size, name_count; u_char *name_table; + ngx_http_lua_regex_compile_t re_comp; + nargs = lua_gettop(L); if (nargs != 2 && nargs != 3 && nargs != 4) { @@ -149,7 +150,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); - ngx_memzero(&re_comp, sizeof(ngx_lua_regex_compile_t)); + ngx_memzero(&re_comp, sizeof(ngx_http_lua_regex_compile_t)); if (nargs >= 3) { opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); @@ -277,7 +278,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) old_pool = ngx_http_lua_pcre_malloc_init(pool); - rc = ngx_lua_regex_compile(&re_comp); + rc = ngx_http_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); @@ -556,7 +557,6 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) ngx_str_t opts; int ovecsize; ngx_http_lua_regex_t *re; - ngx_lua_regex_compile_t re_comp; ngx_http_lua_regex_ctx_t *ctx; const char *msg; int nargs; @@ -568,6 +568,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) pcre_extra *sd = NULL; ngx_http_cleanup_t *cln; + ngx_http_lua_regex_compile_t re_comp; + nargs = lua_gettop(L); if (nargs != 2 && nargs != 3) { @@ -692,7 +694,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) old_pool = ngx_http_lua_pcre_malloc_init(pool); - rc = ngx_lua_regex_compile(&re_comp); + rc = ngx_http_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); @@ -1069,7 +1071,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) static ngx_uint_t -ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_lua_regex_compile_t *re, +ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_http_lua_regex_compile_t *re, ngx_str_t *opts, int narg) { u_char *p; @@ -1172,7 +1174,6 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ngx_str_t tpl; ngx_http_lua_main_conf_t *lmcf = NULL; ngx_pool_t *pool, *old_pool; - ngx_lua_regex_compile_t re_comp; const char *msg; ngx_int_t rc; ngx_uint_t n; @@ -1193,6 +1194,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) int name_entry_size, name_count; u_char *name_table; + ngx_http_lua_regex_compile_t re_comp; ngx_http_lua_complex_value_t *ctpl = NULL; ngx_http_lua_compile_complex_value_t ccv; @@ -1236,7 +1238,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) return luaL_argerror(L, 3, msg); } - ngx_memzero(&re_comp, sizeof(ngx_lua_regex_compile_t)); + ngx_memzero(&re_comp, sizeof(ngx_http_lua_regex_compile_t)); if (nargs == 4) { opts.data = (u_char *) luaL_checklstring(L, 4, &opts.len); @@ -1362,7 +1364,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) old_pool = ngx_http_lua_pcre_malloc_init(pool); - rc = ngx_lua_regex_compile(&re_comp); + rc = ngx_http_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); @@ -1823,7 +1825,7 @@ ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd) static ngx_int_t -ngx_lua_regex_compile(ngx_lua_regex_compile_t *rc) +ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc) { int n, erroff; char *p; From d98a193d4ced98cc2b7dd4170fc72a375b8073c4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 22 Apr 2013 16:14:56 -0700 Subject: [PATCH 0074/1981] added a (passing) test for using ndk.set_var.* in the context of ngx.timer callbacks. --- t/018-ndk.t | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/t/018-ndk.t b/t/018-ndk.t index 52bc761edc..9910107fdd 100644 --- a/t/018-ndk.t +++ b/t/018-ndk.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -146,6 +146,30 @@ a b GET /read --- response_body ok +--- wait: 0.1 --- error_log foo = a b + + +=== TEST 9: ngx.timer.* +--- config + location /read { + echo ok; + log_by_lua ' + ngx.timer.at(0, function () + local foo = ndk.set_var.set_unescape_uri("a%20b") + ngx.log(ngx.WARN, "foo = ", foo) + end) + '; + } +--- request +GET /read +--- response_body +ok +--- wait: 0.1 +--- error_log +foo = a b +--- no_error_log +[error] + From 6afcc17ff157ff55a341d72a4acde62e3e0d61c6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 22 Apr 2013 17:02:11 -0700 Subject: [PATCH 0075/1981] feature: ngx.get_phase() now returns the string "timer" when being invoked within a user callback function for ngx.timer.*. --- src/ngx_http_lua_phase.c | 4 ++++ t/089-phase.t | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index b6a4a201a8..6b43110941 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -71,6 +71,10 @@ ngx_http_lua_ngx_get_phase(lua_State *L) lua_pushliteral(L, "body_filter"); break; + case NGX_HTTP_LUA_CONTEXT_TIMER: + lua_pushliteral(L, "timer"); + break; + default: return luaL_error(L, "unknown phase: %d", (int) ctx->context); } diff --git a/t/089-phase.t b/t/089-phase.t index 3e0cd8c731..5a28f596e2 100644 --- a/t/089-phase.t +++ b/t/089-phase.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 - 1); +plan tests => repeat_each() * (blocks() * 2); #no_diff(); #no_long_string(); @@ -137,3 +137,26 @@ GET /lua --- error_log log + + +=== TEST 9: get_phase in ngx.timer callback +--- config + location /lua { + echo "OK"; + log_by_lua ' + local function f() + ngx.log(ngx.WARN, "current phase: ", ngx.get_phase()) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.log(ngx.ERR, "failed to add timer: ", err) + end + '; + } +--- request +GET /lua +--- no_error_log +[error] +--- error_log +current phase: timer + From 656551e6181369ff62608cef57f219dc11a8bf3c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 22 Apr 2013 17:18:47 -0700 Subject: [PATCH 0076/1981] documented ngx.timer.at, lua_max_pending_timers, lua_max_running_timers, and other recent changes. --- README | 441 +++++++++++++++++++++++++++-------------- README.markdown | 422 ++++++++++++++++++++++++++------------- doc/HttpLuaModule.wiki | 407 +++++++++++++++++++++++++------------ 3 files changed, 864 insertions(+), 406 deletions(-) diff --git a/README b/README index 52cecdd3cf..c3565bfdde 100644 --- a/README +++ b/README @@ -180,10 +180,10 @@ Synopsis } Description - This module embeds Lua, via the standard Lua interpreter or LuaJIT 2.0 - (), into Nginx and by leveraging Nginx's - subrequests, allows the integration of the powerful Lua threads (Lua - coroutines) into the Nginx event model. + This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT + 2.0 (), into Nginx and by leveraging + Nginx's subrequests, allows the integration of the powerful Lua threads + (Lua coroutines) into the Nginx event model. Unlike Apache's mod_lua () and Lighttpd's @@ -1347,6 +1347,40 @@ Directives See also ngx.on_abort. + lua_max_pending_timers + syntax: *lua_max_pending_timers * + + default: *lua_max_pending_timers 1024* + + context: *http* + + Controls the maximum number of pending timers allowed. + + Pending timers are those timers that have not expired yet. + + When exceeding this limit, the ngx.timer.at call will immediately return + "nil" and the error string "too many pending timers". + + This directive was first introduced in the "v0.8.0" release. + + lua_max_running_timers + syntax: *lua_max_running_timers * + + default: *lua_max_running_timers 256* + + context: *http* + + Controls the maximum number of "running timers" allowed. + + Running timers are those timers whose user callback functions are still + running. + + When exceeding this limit, Nginx will stop running the callbacks of + newly expired timers and log an error message "N lua_max_running_timers + are not enough" where "N" is the current value of this directive. + + This directive was first introduced in the "v0.8.0" release. + Nginx API for Lua Introduction The various *_by_lua and *_by_lua_file configuration directives serve as @@ -1479,7 +1513,7 @@ Nginx API for Lua Core constants context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, - *log_by_lua** + *log_by_lua*, ngx.timer.** ngx.OK (0) ngx.ERROR (-1) @@ -1504,7 +1538,8 @@ Nginx API for Lua HTTP method constants context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, - content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** + content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, + ngx.timer.** ngx.HTTP_GET ngx.HTTP_HEAD @@ -1518,7 +1553,8 @@ Nginx API for Lua HTTP status constants context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, - content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** + content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, + ngx.timer.** value = ngx.HTTP_OK (200) value = ngx.HTTP_CREATED (201) @@ -1540,7 +1576,7 @@ Nginx API for Lua Nginx log level constants context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua, log_by_lua** + header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ngx.STDERR ngx.EMERG @@ -1558,7 +1594,8 @@ Nginx API for Lua syntax: *print(...)* context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, - content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** + content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, + ngx.timer.** Writes argument values into the nginx "error.log" file with the "ngx.NOTICE" log level. @@ -1580,7 +1617,7 @@ Nginx API for Lua ngx.ctx context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua, log_by_lua** + header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx @@ -3063,7 +3100,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Log arguments concatenated to error.log with the given logging level. @@ -3192,7 +3229,7 @@ Nginx API for Lua ngx.sleep syntax: *ngx.sleep(seconds)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -3207,7 +3244,7 @@ Nginx API for Lua syntax: *newstr = ngx.escape_uri(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Escape "str" as a URI component. @@ -3215,7 +3252,7 @@ Nginx API for Lua syntax: *newstr = ngx.unescape_uri(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unescape "str" as an escaped URI component. @@ -3231,7 +3268,7 @@ Nginx API for Lua syntax: *str = ngx.encode_args(table)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encode the Lua table to a query args string according to the URI encoded rules. @@ -3275,7 +3312,7 @@ Nginx API for Lua syntax: *table = ngx.decode_args(str, max_args?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes a URI encoded query-string into a Lua table. This is the inverse function of ngx.encode_args. @@ -3299,7 +3336,7 @@ Nginx API for Lua syntax: *newstr = ngx.encode_base64(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encode "str" to a base64 digest. @@ -3307,7 +3344,7 @@ Nginx API for Lua syntax: *newstr = ngx.decode_base64(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes the "str" argument as a base64 digest to the raw form. Returns "nil" if "str" is not well formed. @@ -3316,7 +3353,7 @@ Nginx API for Lua syntax: *intval = ngx.crc32_short(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the "str" argument. @@ -3334,7 +3371,7 @@ Nginx API for Lua syntax: *intval = ngx.crc32_long(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the "str" argument. @@ -3352,7 +3389,7 @@ Nginx API for Lua syntax: *digest = ngx.hmac_sha1(secret_key, str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Computes the HMAC-SHA1 () digest of the argument "str" and turns the result using the secret key @@ -3383,7 +3420,7 @@ Nginx API for Lua syntax: *digest = ngx.md5(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the hexadecimal representation of the MD5 digest of the "str" argument. @@ -3404,7 +3441,7 @@ Nginx API for Lua syntax: *digest = ngx.md5_bin(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the MD5 digest of the "str" argument. @@ -3414,7 +3451,7 @@ Nginx API for Lua syntax: *digest = ngx.sha1_bin(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the SHA-1 digest of the "str" argument. @@ -3427,7 +3464,7 @@ Nginx API for Lua syntax: *quoted_value = ngx.quote_sql_str(raw_value)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -3436,7 +3473,7 @@ Nginx API for Lua syntax: *str = ngx.today()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns current date (in the format "yyyy-mm-dd") from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3447,7 +3484,7 @@ Nginx API for Lua syntax: *secs = ngx.time()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date @@ -3460,7 +3497,7 @@ Nginx API for Lua syntax: *secs = ngx.now()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the @@ -3476,7 +3513,7 @@ Nginx API for Lua syntax: *ngx.update_time()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -3487,7 +3524,7 @@ Nginx API for Lua syntax: *str = ngx.localtime()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format "yyyy-mm-dd hh:mm:ss") of the nginx cached time (no syscall involved unlike Lua's os.date @@ -3499,7 +3536,7 @@ Nginx API for Lua syntax: *str = ngx.utctime()* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format "yyyy-mm-dd hh:mm:ss") of the nginx cached time (no syscall involved unlike Lua's os.date @@ -3511,7 +3548,7 @@ Nginx API for Lua syntax: *str = ngx.cookie_time(sec)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formated string can be used as the cookie expiration time. The parameter "sec" is the time stamp in seconds (like those returned from @@ -3524,7 +3561,7 @@ Nginx API for Lua syntax: *str = ngx.http_time(sec)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formated string can be used as the http header time (for example, being used in "Last-Modified" header). The parameter "sec" is @@ -3537,7 +3574,7 @@ Nginx API for Lua syntax: *sec = ngx.parse_http_time(str)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Parse the http time string (as returned by ngx.http_time) into seconds. Returns the seconds or "nil" if the input string is in bad forms. @@ -3560,7 +3597,7 @@ Nginx API for Lua syntax: *captures, err = ngx.re.match(subject, regex, options?, ctx?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Matches the "subject" string using the Perl compatible regular expression "regex" with the optional "options". @@ -3711,7 +3748,7 @@ Nginx API for Lua syntax: *iterator, err = ngx.re.gmatch(subject, regex, options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to ngx.re.match, but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the "" @@ -3788,7 +3825,7 @@ Nginx API for Lua syntax: *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Substitutes the first match of the Perl compatible regular expression "regex" on the "subject" argument string with the string or function @@ -3858,7 +3895,7 @@ Nginx API for Lua options?)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like ngx.re.sub, but does global substitution. @@ -3890,7 +3927,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Fetching the shm-based Lua dictionary object for the shared memory zone named "DICT" defined by the lua_shared_dict directive. @@ -3967,7 +4004,7 @@ Nginx API for Lua syntax: *value, flags = ngx.shared.DICT:get(key)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Retrieving the value in the dictionary ngx.shared.DICT for the key "key". If the key does not exist or has been expired, then "nil" will be @@ -4003,7 +4040,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Unconditionally sets a key-value pair into the shm-based dictionary ngx.shared.DICT. Returns three values: @@ -4073,7 +4110,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Similar to the set method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared @@ -4090,7 +4127,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Just like the set method, but only stores the key-value pair into the dictionary ngx.shared.DICT if the key does *not* exist. @@ -4109,7 +4146,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Similar to the add method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared @@ -4126,7 +4163,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Just like the set method, but only stores the key-value pair into the dictionary ngx.shared.DICT if the key *does* exist. @@ -4144,7 +4181,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Unconditionally removes the key-value pair from the shm-based dictionary ngx.shared.DICT. @@ -4160,7 +4197,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Increments the (numerical) value for "key" in the shm-based dictionary ngx.shared.DICT by the step value "value". Returns the new resulting @@ -4185,7 +4222,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Flushes out all the items in the dictionary. @@ -4198,7 +4235,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional "max_count" argument. When the @@ -4214,7 +4251,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Fetch a list of the keys from the dictionary, up to "". @@ -4232,7 +4269,7 @@ Nginx API for Lua ngx.socket.udp syntax: *udpsock = ngx.socket.udp()* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following @@ -4262,7 +4299,7 @@ Nginx API for Lua syntax: *ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is @@ -4323,7 +4360,7 @@ Nginx API for Lua udpsock:send syntax: *ok, err = udpsock:send(data)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sends data on the current UDP or datagram unix domain socket object. @@ -4341,7 +4378,7 @@ Nginx API for Lua udpsock:receive syntax: *data, err = udpsock:receive(size?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, "size". @@ -4378,7 +4415,7 @@ Nginx API for Lua udpsock:close syntax: *ok, err = udpsock:close()* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Closes the current UDP or datagram unix domain socket. It returns the 1 in case of success and returns "nil" with a string describing the error @@ -4394,7 +4431,7 @@ Nginx API for Lua udpsock:settimeout syntax: *udpsock:settimeout(time)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Set the timeout value in milliseconds for subsequent socket operations (like receive). @@ -4407,7 +4444,7 @@ Nginx API for Lua ngx.socket.tcp syntax: *tcpsock = ngx.socket.tcp()* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following @@ -4446,7 +4483,7 @@ Nginx API for Lua syntax: *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -4528,7 +4565,7 @@ Nginx API for Lua tcpsock:send syntax: *bytes, err = tcpsock:send(data)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -4563,7 +4600,7 @@ Nginx API for Lua syntax: *data, err, partial = tcpsock:receive(pattern?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Receives data from the connected socket according to the reading pattern or size. @@ -4614,7 +4651,7 @@ Nginx API for Lua tcpsock:receiveuntil syntax: *iterator = tcpsock:receiveuntil(pattern, options?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -4727,7 +4764,7 @@ Nginx API for Lua tcpsock:close syntax: *ok, err = tcpsock:close()* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Closes the current TCP or stream unix domain socket. It returns the 1 in case of success and returns "nil" with a string describing the error @@ -4748,7 +4785,7 @@ Nginx API for Lua tcpsock:settimeout syntax: *tcpsock:settimeout(time)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Set the timeout value in milliseconds for subsequent socket operations (connect, receive, and iterators returned from receiveuntil). @@ -4766,7 +4803,7 @@ Nginx API for Lua tcpsock:setoption syntax: *tcpsock:setoption(option, value?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This function is added for LuaSocket () API @@ -4778,7 +4815,7 @@ Nginx API for Lua tcpsock:setkeepalive syntax: *ok, err = tcpsock:setkeepalive(timeout?, size?)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other connect method @@ -4822,7 +4859,7 @@ Nginx API for Lua tcpsock:getreusedtimes syntax: *count, err = tcpsock:getreusedtimes()* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This method returns the (successfully) reused times for the current connection. In case of error, it returns "nil" and a string describing @@ -4842,7 +4879,7 @@ Nginx API for Lua syntax: *tcpsock, err = ngx.socket.connect("unix:/path/to/unix-domain.socket")* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This function is a shortcut for combining ngx.socket.tcp() and the connect() method call in a single operation. It is actually implemented @@ -4866,7 +4903,7 @@ Nginx API for Lua context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, - log_by_lua** + log_by_lua*, ngx.timer.** Retrieves the current running phase name. Possible return values are @@ -4889,86 +4926,16 @@ Nginx API for Lua "body_filter" for the context of body_filter_by_lua or body_filter_by_lua_file. =item * - "log" for the context of log_by_lua or log_by_lua_file. - - This API was first introduced in the "v0.5.10" release. - - coroutine.create - syntax: *co = coroutine.create(f)* - - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - - Creates a user Lua coroutines with a Lua function, and returns a - coroutine object. - - Similar to the standard Lua coroutine.create - () API, - but works in the context of the Lua coroutines created by ngx_lua. - - This API was first introduced in the "v0.6.0" release. - - coroutine.resume - syntax: *ok, ... = coroutine.resume(co, ...)* - - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - - Resumes the executation of a user Lua coroutine object previously - yielded or just created. - - Similar to the standard Lua coroutine.resume - () API, - but works in the context of the Lua coroutines created by ngx_lua. - - This API was first introduced in the "v0.6.0" release. - - coroutine.yield - syntax: *... = coroutine.yield(co, ...)* - - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - - Yields the executation of the current user Lua coroutine. - - Similar to the standard Lua coroutine.yield - () API, - but works in the context of the Lua coroutines created by ngx_lua. - - This API was first introduced in the "v0.6.0" release. - - coroutine.wrap - syntax: *co = coroutine.wrap(f)* - - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - - Similar to the standard Lua coroutine.wrap - () API, - but works in the context of the Lua coroutines created by ngx_lua. - - This API was first introduced in the "v0.6.0" release. - - coroutine.running - syntax: *co = coroutine.running()* + "log" for the context of log_by_lua or log_by_lua_file. =item * - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + "timer" for the context of user callback functions for ngx.timer.*. - Identical to the standard Lua coroutine.running - () API. - - This API was first enabled in the "v0.6.0" release. - - coroutine.status - syntax: *status = coroutine.status(co)* - - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - - Identical to the standard Lua coroutine.status - () API. - - This API was first enabled in the "v0.6.0" release. + This API was first introduced in the "v0.5.10" release. ngx.thread.spawn syntax: *co = ngx.thread.spawn(func, arg1, arg2, ...)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Spawns a new user "light thread" with the Lua function "func" as well as those optional arguments "arg1", "arg2", and etc. Returns a Lua thread @@ -5139,7 +5106,7 @@ Nginx API for Lua ngx.thread.wait syntax: *ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)* - context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an @@ -5285,11 +5252,125 @@ Nginx API for Lua See also lua_check_client_abort. + ngx.timer.at + syntax: *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, + ...)* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + + Creates an Nginx timer with a user callback function as well as optional + user arguments. + + The first argument, "delay", specifies the delay for the timer, in + seconds. One can specify fractional seconds like 0.001 to mean 1 + millisecond here. 0 delay can also be specified, in which case the timer + will immediately expire when the current handler yields execution. + + The second argument, "callback", can be any Lua function, which will be + invoked later in a background "light thread" after the delay specified. + The user callback will be called automatically by the Nginx core with + the arguments "premature", "user_arg1", "user_arg2", and etc, where the + "premature" argument takes a boolean value indicating whether it is a + premature timer expiration or not, and "user_arg1", "user_arg2", and + etc, are those (extra) user arguments specified when calling + "ngx.timer.at" as the remaining arguments. + + Premature timer expiration happens when the Nginx worker process is + trying to shut down, as in an Nginx configuration reload triggered by + the "HUP" signal or in an Nginx server shutdown. When the Nginx worker + is trying to shut down, one can no longer call "ngx.timer.at" to create + new timers and in that case "ngx.timer.at" will return "nil" and a + string describing the error, that is, "process exiting". + + When a timer expires, the user Lua code in the timer callback is running + in a "light thread" detached completely from the original request + creating the timer. So objects with the same lifetime as the request + creating them, like cosockets, cannot be shared between the original + request and the timer user callback function. + + Here is a simple example: + + location / { + ... + log_by_lua ' + local function push_data(premature, uri, args, status) + -- push the data uri, args, and status to the remote + -- via ngx.socket.tcp or ngx.socket.udp + -- (one may want to buffer the data in Lua a bit to + -- save I/O operations) + end + local ok, err = ngx.timer.at(0, push_data, + ngx.var.uri, ngx.var.args, ngx.header.status) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + '; + } + + One can also create infinite re-occuring timers, for instance, a timer + getting triggered every 5 seconds, by calling "ngx.timer.at" recursively + in the timer callback function. Here is such an example, + + local delay = 5 + local handler + handler = function (premature) + -- do some routine job in Lua just like a cron job + if premature then + return + end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + end + + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + + Because timer callbacks run in the background and their running time + will not add to any client request's response time, they can easily + accumulate in the server and exhaust system resources due to either Lua + programming mistakes or just too much client traffic. To prevent extreme + consequences like crashing the Nginx server, there are built-in + limitations on both the number of "pending timers" and the number of + "running timers" in an Nginx worker process. The "pending timers" here + mean timers that have not yet been expired and "running timers" are + those whose user callbacks are currently running. + + The maximal number of pending timers allowed in an Nginx worker is + constrolled by the lua_max_pending_timers directive. The maximal number + of running timers is controlled by the lua_max_running_timers directive. + + According to the current implementation, each "running timer" will take + one (fake) connection record from the global connection record list + configured by the standard worker_connections directive in "nginx.conf". + So ensure that the worker_connections directive is set to a large enough + value that takes into account both the real connections and fake + connections required by timer callbacks (as limited by the + lua_max_running_timers directive). + + A lot of the Lua APIs for Nginx are enabled in the context of the timer + callbacks, like stream/datagram cosockets (ngx.socket.tcp and + ngx.socket.udp), shared memory dictionaries (ngx.shared.DICT), user + coroutines (coroutine.*), user "light threads" (ngx.thread.*), ngx.exit, + ngx.now/ngx.time, ngx.md5/ngx.sha1, are all allowed. But the subrequest + API (like ngx.location.capture), the ngx.req.* API, the downstream + output API (like ngx.say, ngx.print, and ngx.flush) are explicitly + disabled in this context. + + This API was first introduced in the "v0.8.0" release. + ndk.set_var.DIRECTIVE syntax: *res = ndk.set_var.DIRECTIVE_NAME* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua*, log_by_lua** + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** This mechanism allows calling other nginx C modules' directives that are implemented by Nginx Devel Kit @@ -5340,6 +5421,78 @@ Nginx API for Lua This feature requires the ngx_devel_kit () module. + coroutine.create + syntax: *co = coroutine.create(f)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Creates a user Lua coroutines with a Lua function, and returns a + coroutine object. + + Similar to the standard Lua coroutine.create + () API, + but works in the context of the Lua coroutines created by ngx_lua. + + This API was first introduced in the "v0.6.0" release. + + coroutine.resume + syntax: *ok, ... = coroutine.resume(co, ...)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Resumes the executation of a user Lua coroutine object previously + yielded or just created. + + Similar to the standard Lua coroutine.resume + () API, + but works in the context of the Lua coroutines created by ngx_lua. + + This API was first introduced in the "v0.6.0" release. + + coroutine.yield + syntax: *... = coroutine.yield(co, ...)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Yields the executation of the current user Lua coroutine. + + Similar to the standard Lua coroutine.yield + () API, + but works in the context of the Lua coroutines created by ngx_lua. + + This API was first introduced in the "v0.6.0" release. + + coroutine.wrap + syntax: *co = coroutine.wrap(f)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Similar to the standard Lua coroutine.wrap + () API, + but works in the context of the Lua coroutines created by ngx_lua. + + This API was first introduced in the "v0.6.0" release. + + coroutine.running + syntax: *co = coroutine.running()* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Identical to the standard Lua coroutine.running + () API. + + This API was first enabled in the "v0.6.0" release. + + coroutine.status + syntax: *status = coroutine.status(co)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + + Identical to the standard Lua coroutine.status + () API. + + This API was first enabled in the "v0.6.0" release. + Lua/LuaJIT bytecode support As from the "v0.5.0rc32" release, all *_by_lua_file configure directives (such as content_by_lua_file) support loading Lua 5.1 and LuaJIT 2.0 raw diff --git a/README.markdown b/README.markdown index 5e5b0b29cd..adc2c67fd3 100644 --- a/README.markdown +++ b/README.markdown @@ -193,7 +193,7 @@ Synopsis Description =========== -This module embeds Lua, via the standard Lua interpreter or [LuaJIT 2.0](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [Apache's mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -1183,6 +1183,40 @@ This directive was first introduced in the `v0.7.4` release. See also [ngx.on_abort](http://wiki.nginx.org/HttpLuaModule#ngx.on_abort). +lua_max_pending_timers +---------------------- + +**syntax:** *lua_max_pending_timers <count>* + +**default:** *lua_max_pending_timers 1024* + +**context:** *http* + +Controls the maximum number of pending timers allowed. + +Pending timers are those timers that have not expired yet. + +When exceeding this limit, the [ngx.timer.at](http://wiki.nginx.org/HttpLuaModule#ngx.timer.at) call will immediately return `nil` and the error string "too many pending timers". + +This directive was first introduced in the `v0.8.0` release. + +lua_max_running_timers +---------------------- + +**syntax:** *lua_max_running_timers <count>* + +**default:** *lua_max_running_timers 256* + +**context:** *http* + +Controls the maximum number of "running timers" allowed. + +Running timers are those timers whose user callback functions are still running. + +When exceeding this limit, Nginx will stop running the callbacks of newly expired timers and log an error message "N lua_max_running_timers are not enough" where "N" is the current value of this directive. + +This directive was first introduced in the `v0.8.0` release. + Nginx API for Lua ================= Introduction @@ -1300,7 +1334,7 @@ to prevent (temporary) memory leaking within the current request's lifetime. Core constants -------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, *log_by_lua*, ngx.timer.** ngx.OK (0) @@ -1322,7 +1356,7 @@ The `ngx.DECLINED` constant was first introduced in the `v0.5.0rc19` release. HTTP method constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ngx.HTTP_GET @@ -1337,7 +1371,7 @@ These constants are usually used in [ngx.location.capture](http://wiki.nginx.org HTTP status constants --------------------- -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** value = ngx.HTTP_OK (200) @@ -1361,7 +1395,7 @@ HTTP status constants Nginx log level constants ------------------------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** ngx.STDERR @@ -1381,7 +1415,7 @@ print ----- **syntax:** *print(...)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** Writes argument values into the nginx `error.log` file with the `ngx.NOTICE` log level. @@ -1397,7 +1431,7 @@ There is a hard coded `2048` byte limitation on error message lengths in the Ngi ngx.ctx ------- -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.** This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). @@ -2842,7 +2876,7 @@ ngx.log ------- **syntax:** *ngx.log(log_level, ...)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Log arguments concatenated to error.log with the given logging level. @@ -2945,7 +2979,7 @@ ngx.sleep --------- **syntax:** *ngx.sleep(seconds)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -2959,7 +2993,7 @@ ngx.escape_uri -------------- **syntax:** *newstr = ngx.escape_uri(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Escape `str` as a URI component. @@ -2967,7 +3001,7 @@ ngx.unescape_uri ---------------- **syntax:** *newstr = ngx.unescape_uri(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unescape `str` as an escaped URI component. @@ -2987,7 +3021,7 @@ ngx.encode_args --------------- **syntax:** *str = ngx.encode_args(table)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encode the Lua table to a query args string according to the URI encoded rules. @@ -3039,7 +3073,7 @@ ngx.decode_args --------------- **syntax:** *table = ngx.decode_args(str, max_args?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes a URI encoded query-string into a Lua table. This is the inverse function of [ngx.encode_args](http://wiki.nginx.org/HttpLuaModule#ngx.encode_args). @@ -3059,7 +3093,7 @@ ngx.encode_base64 ----------------- **syntax:** *newstr = ngx.encode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Encode `str` to a base64 digest. @@ -3067,7 +3101,7 @@ ngx.decode_base64 ----------------- **syntax:** *newstr = ngx.decode_base64(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Decodes the `str` argument as a base64 digest to the raw form. Returns `nil` if `str` is not well formed. @@ -3075,7 +3109,7 @@ ngx.crc32_short --------------- **syntax:** *intval = ngx.crc32_short(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -3089,7 +3123,7 @@ ngx.crc32_long -------------- **syntax:** *intval = ngx.crc32_long(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Calculates the CRC-32 (Cyclic Redundancy Code) digest for the `str` argument. @@ -3103,7 +3137,7 @@ ngx.hmac_sha1 ------------- **syntax:** *digest = ngx.hmac_sha1(secret_key, str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Computes the [HMAC-SHA1](http://en.wikipedia.org/wiki/HMAC) digest of the argument `str` and turns the result using the secret key ``. @@ -3132,7 +3166,7 @@ ngx.md5 ------- **syntax:** *digest = ngx.md5(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the hexadecimal representation of the MD5 digest of the `str` argument. @@ -3156,7 +3190,7 @@ ngx.md5_bin ----------- **syntax:** *digest = ngx.md5_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the MD5 digest of the `str` argument. @@ -3166,7 +3200,7 @@ ngx.sha1_bin ------------ **syntax:** *digest = ngx.sha1_bin(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the binary form of the SHA-1 digest of the `str` argument. @@ -3178,7 +3212,7 @@ ngx.quote_sql_str ----------------- **syntax:** *quoted_value = ngx.quote_sql_str(raw_value)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a quoted SQL string literal according to the MySQL quoting rules. @@ -3186,7 +3220,7 @@ ngx.today --------- **syntax:** *str = ngx.today()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns current date (in the format `yyyy-mm-dd`) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3196,7 +3230,7 @@ ngx.time -------- **syntax:** *secs = ngx.time()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3206,7 +3240,7 @@ ngx.now ------- **syntax:** *secs = ngx.now()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3218,7 +3252,7 @@ ngx.update_time --------------- **syntax:** *ngx.update_time()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -3228,7 +3262,7 @@ ngx.localtime ------------- **syntax:** *str = ngx.localtime()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -3238,7 +3272,7 @@ ngx.utctime ----------- **syntax:** *str = ngx.utctime()* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the current time stamp (in the format `yyyy-mm-dd hh:mm:ss`) of the nginx cached time (no syscall involved unlike Lua's [os.date](http://www.lua.org/manual/5.1/manual.html#pdf-os.date) function). @@ -3248,7 +3282,7 @@ ngx.cookie_time --------------- **syntax:** *str = ngx.cookie_time(sec)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formated string can be used as the cookie expiration time. The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time)). @@ -3261,7 +3295,7 @@ ngx.http_time ------------- **syntax:** *str = ngx.http_time(sec)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the time stamp in seconds (like those returned from [ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time)). @@ -3274,7 +3308,7 @@ ngx.parse_http_time ------------------- **syntax:** *sec = ngx.parse_http_time(str)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Parse the http time string (as returned by [ngx.http_time](http://wiki.nginx.org/HttpLuaModule#ngx.http_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms. @@ -3297,7 +3331,7 @@ ngx.re.match ------------ **syntax:** *captures, err = ngx.re.match(subject, regex, options?, ctx?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Matches the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. @@ -3440,7 +3474,7 @@ ngx.re.gmatch ------------- **syntax:** *iterator, err = ngx.re.gmatch(subject, regex, options?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to [ngx.re.match](http://wiki.nginx.org/HttpLuaModule#ngx.re.match), but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the `` string argument with the PCRE `regex`. @@ -3514,7 +3548,7 @@ ngx.re.sub ---------- **syntax:** *newstr, n, err = ngx.re.sub(subject, regex, replace, options?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Substitutes the first match of the Perl compatible regular expression `regex` on the `subject` argument string with the string or function argument `replace`. The optional `options` argument has exactly the same meaning as in [ngx.re.match](http://wiki.nginx.org/HttpLuaModule#ngx.re.match). @@ -3574,7 +3608,7 @@ ngx.re.gsub ----------- **syntax:** *newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like [ngx.re.sub](http://wiki.nginx.org/HttpLuaModule#ngx.re.sub), but does global substitution. @@ -3608,7 +3642,7 @@ ngx.shared.DICT --------------- **syntax:** *dict = ngx.shared.DICT* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](http://wiki.nginx.org/HttpLuaModule#lua_shared_dict) directive. @@ -3673,7 +3707,7 @@ ngx.shared.DICT.get ------------------- **syntax:** *value, flags = ngx.shared.DICT:get(key)* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Retrieving the value in the dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) for the key `key`. If the key does not exist or has been expired, then `nil` will be returned. @@ -3705,7 +3739,7 @@ ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unconditionally sets a key-value pair into the shm-based dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). Returns three values: @@ -3749,7 +3783,7 @@ ngx.shared.DICT.safe_set ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to the [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -3761,7 +3795,7 @@ ngx.shared.DICT.add ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like the [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) if the key does *not* exist. @@ -3775,7 +3809,7 @@ ngx.shared.DICT.safe_add ------------------------ **syntax:** *ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Similar to the [add](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.add) method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return `nil` and the string "no memory". @@ -3787,7 +3821,7 @@ ngx.shared.DICT.replace ----------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Just like the [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) method, but only stores the key-value pair into the dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) if the key *does* exist. @@ -3801,7 +3835,7 @@ ngx.shared.DICT.delete ---------------------- **syntax:** *ngx.shared.DICT:delete(key)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Unconditionally removes the key-value pair from the shm-based dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). @@ -3815,7 +3849,7 @@ ngx.shared.DICT.incr -------------------- **syntax:** *newval, err = ngx.shared.DICT:incr(key, value)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise. @@ -3833,7 +3867,7 @@ ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Flushes out all the items in the dictionary. @@ -3845,7 +3879,7 @@ ngx.shared.DICT.flush_expired ----------------------------- **syntax:** *flushed = ngx.shared.DICT:flush_expired(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -3857,7 +3891,7 @@ ngx.shared.DICT.get_keys ------------------------ **syntax:** *keys = ngx.shared.DICT:get_keys(max_count?)* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Fetch a list of the keys from the dictionary, up to ``. @@ -3871,7 +3905,7 @@ ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -3893,7 +3927,7 @@ udpsock:setpeername **syntax:** *ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -3947,7 +3981,7 @@ udpsock:send ------------ **syntax:** *ok, err = udpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sends data on the current UDP or datagram unix domain socket object. @@ -3961,7 +3995,7 @@ udpsock:receive --------------- **syntax:** *data, err = udpsock:receive(size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, `size`. @@ -3993,7 +4027,7 @@ udpsock:close ------------- **syntax:** *ok, err = udpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Closes the current UDP or datagram unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -4005,7 +4039,7 @@ udpsock:settimeout ------------------ **syntax:** *udpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Set the timeout value in milliseconds for subsequent socket operations (like [receive](http://wiki.nginx.org/HttpLuaModule#udpsock:receive)). @@ -4017,7 +4051,7 @@ ngx.socket.tcp -------------- **syntax:** *tcpsock = ngx.socket.tcp()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -4043,7 +4077,7 @@ tcpsock:connect **syntax:** *ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -4116,7 +4150,7 @@ tcpsock:send ------------ **syntax:** *bytes, err = tcpsock:send(data)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -4143,7 +4177,7 @@ tcpsock:receive **syntax:** *data, err, partial = tcpsock:receive(pattern?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Receives data from the connected socket according to the reading pattern or size. @@ -4180,7 +4214,7 @@ tcpsock:receiveuntil -------------------- **syntax:** *iterator = tcpsock:receiveuntil(pattern, options?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -4271,7 +4305,7 @@ tcpsock:close ------------- **syntax:** *ok, err = tcpsock:close()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Closes the current TCP or stream unix domain socket. It returns the `1` in case of success and returns `nil` with a string describing the error otherwise. @@ -4285,7 +4319,7 @@ tcpsock:settimeout ------------------ **syntax:** *tcpsock:settimeout(time)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Set the timeout value in milliseconds for subsequent socket operations ([connect](http://wiki.nginx.org/HttpLuaModule#tcpsock:connect), [receive](http://wiki.nginx.org/HttpLuaModule#tcpsock:receive), and iterators returned from [receiveuntil](http://wiki.nginx.org/HttpLuaModule#tcpsock:receiveuntil)). @@ -4299,7 +4333,7 @@ tcpsock:setoption ----------------- **syntax:** *tcpsock:setoption(option, value?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This function is added for [LuaSocket](http://w3.impa.br/~diego/software/luasocket/tcp.html) API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -4309,7 +4343,7 @@ tcpsock:setkeepalive -------------------- **syntax:** *ok, err = tcpsock:setkeepalive(timeout?, size?)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [connect](http://wiki.nginx.org/HttpLuaModule#tcpsock:connect) method calls request it or the associated maximal idle timeout is expired. @@ -4333,7 +4367,7 @@ tcpsock:getreusedtimes ---------------------- **syntax:** *count, err = tcpsock:getreusedtimes()* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This method returns the (successfully) reused times for the current connection. In case of error, it returns `nil` and a string describing the error. @@ -4347,7 +4381,7 @@ ngx.socket.connect **syntax:** *tcpsock, err = ngx.socket.connect("unix:/path/to/unix-domain.socket")* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** This function is a shortcut for combining [ngx.socket.tcp()](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and the [connect()](http://wiki.nginx.org/HttpLuaModule#tcpsock:connect) method call in a single operation. It is actually implemented like this: @@ -4368,7 +4402,7 @@ ngx.get_phase ------------- **syntax:** *str = ngx.get_phase()* -**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Retrieves the current running phase name. Possible return values are @@ -4388,80 +4422,16 @@ Retrieves the current running phase name. Possible return values are for the context of [body_filter_by_lua](http://wiki.nginx.org/HttpLuaModule#body_filter_by_lua) or [body_filter_by_lua_file](http://wiki.nginx.org/HttpLuaModule#body_filter_by_lua_file). * `log` for the context of [log_by_lua](http://wiki.nginx.org/HttpLuaModule#log_by_lua) or [log_by_lua_file](http://wiki.nginx.org/HttpLuaModule#log_by_lua_file). +* `timer` + for the context of user callback functions for [ngx.timer.*](http://wiki.nginx.org/HttpLuaModule#ngx.timer.at). This API was first introduced in the `v0.5.10` release. -coroutine.create ----------------- -**syntax:** *co = coroutine.create(f)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Creates a user Lua coroutines with a Lua function, and returns a coroutine object. - -Similar to the standard Lua [coroutine.create](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.create) API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the `v0.6.0` release. - -coroutine.resume ----------------- -**syntax:** *ok, ... = coroutine.resume(co, ...)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Resumes the executation of a user Lua coroutine object previously yielded or just created. - -Similar to the standard Lua [coroutine.resume](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.resume) API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the `v0.6.0` release. - -coroutine.yield ---------------- -**syntax:** *... = coroutine.yield(co, ...)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Yields the executation of the current user Lua coroutine. - -Similar to the standard Lua [coroutine.yield](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield) API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the `v0.6.0` release. - -coroutine.wrap --------------- -**syntax:** *co = coroutine.wrap(f)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Similar to the standard Lua [coroutine.wrap](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap) API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the `v0.6.0` release. - -coroutine.running ------------------ -**syntax:** *co = coroutine.running()* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Identical to the standard Lua [coroutine.running](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running) API. - -This API was first enabled in the `v0.6.0` release. - -coroutine.status ----------------- -**syntax:** *status = coroutine.status(co)* - -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** - -Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. - -This API was first enabled in the `v0.6.0` release. - ngx.thread.spawn ---------------- **syntax:** *co = ngx.thread.spawn(func, arg1, arg2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Spawns a new user "light thread" with the Lua function `func` as well as those optional arguments `arg1`, `arg2`, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -4592,7 +4562,7 @@ ngx.thread.wait --------------- **syntax:** *ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)* -**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -4724,11 +4694,129 @@ This API was first introduced in the `v0.7.4` release. See also [lua_check_client_abort](http://wiki.nginx.org/HttpLuaModule#lua_check_client_abort). +ngx.timer.at +------------ +**syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Creates an Nginx timer with a user callback function as well as optional user arguments. + +The first argument, `delay`, specifies the delay for the timer, +in seconds. One can specify fractional seconds like `0.001` to mean 1 +millisecond here. `0` delay can also be specified, in which case the +timer will immediately expire when the current handler yields +execution. + +The second argument, `callback`, can +be any Lua function, which will be invoked later in a background +"light thread" after the delay specified. The user callback will be +called automatically by the Nginx core with the arguments `premature`, +`user_arg1`, `user_arg2`, and etc, where the `premature` +argument takes a boolean value indicating whether it is a premature timer +expiration or not, and `user_arg1`, `user_arg2`, and etc, are +those (extra) user arguments specified when calling `ngx.timer.at` +as the remaining arguments. + +Premature timer expiration happens when the Nginx worker process is +trying to shut down, as in an Nginx configuration reload triggered by +the `HUP` signal or in an Nginx server shutdown. When the Nginx worker +is trying to shut down, one can no longer call `ngx.timer.at` to +create new timers and in that case `ngx.timer.at` will return `nil` and +a string describing the error, that is, "process exiting". + +When a timer expires, the user Lua code in the timer callback is +running in a "light thread" detached completely from the original +request creating the timer. So objects with the same lifetime as the +request creating them, like [cosockets](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp), cannot be shared between the +original request and the timer user callback function. + +Here is a simple example: + + + location / { + ... + log_by_lua ' + local function push_data(premature, uri, args, status) + -- push the data uri, args, and status to the remote + -- via ngx.socket.tcp or ngx.socket.udp + -- (one may want to buffer the data in Lua a bit to + -- save I/O operations) + end + local ok, err = ngx.timer.at(0, push_data, + ngx.var.uri, ngx.var.args, ngx.header.status) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + '; + } + + +One can also create infinite re-occuring timers, for instance, a timer getting triggered every `5` seconds, by calling `ngx.timer.at` recursively in the timer callback function. Here is such an example, + + + local delay = 5 + local handler + handler = function (premature) + -- do some routine job in Lua just like a cron job + if premature then + return + end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + end + + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + + +Because timer callbacks run in the background and their running time +will not add to any client request's response time, they can easily +accumulate in the server and exhaust system resources due to either +Lua programming mistakes or just too much client traffic. To prevent +extreme consequences like crashing the Nginx server, there are +built-in limitations on both the number of "pending timers" and the +number of "running timers" in an Nginx worker process. The "pending +timers" here mean timers that have not yet been expired and "running +timers" are those whose user callbacks are currently running. + +The maximal number of pending timers allowed in an Nginx +worker is constrolled by the [lua_max_pending_timers](http://wiki.nginx.org/HttpLuaModule#lua_max_pending_timers) +directive. The maximal number of running timers is controlled by the +[lua_max_running_timers](http://wiki.nginx.org/HttpLuaModule#lua_max_running_timers) directive. + +According to the current implementation, each "running timer" will +take one (fake) connection record from the global connection record +list configured by the standard [worker_connections](http://wiki.nginx.org/EventsModule#worker_connections) directive in +`nginx.conf`. So ensure that the +[worker_connections](http://wiki.nginx.org/EventsModule#worker_connections) directive is set to +a large enough value that takes into account both the real connections +and fake connections required by timer callbacks (as limited by the +[lua_max_running_timers](http://wiki.nginx.org/HttpLuaModule#lua_max_running_timers) directive). + +A lot of the Lua APIs for Nginx are enabled in the context of the timer +callbacks, like stream/datagram cosockets ([ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.socket.udp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.udp)), shared +memory dictionaries ([ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT)), user coroutines ([coroutine.*](http://wiki.nginx.org/HttpLuaModule#coroutine.create)), +user "light threads" ([ngx.thread.*](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn)), [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit), [ngx.now](http://wiki.nginx.org/HttpLuaModule#ngx.now)/[ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time), +[ngx.md5](http://wiki.nginx.org/HttpLuaModule#ngx.md5)/[ngx.sha1](http://wiki.nginx.org/HttpLuaModule#ngx.sha1), are all allowed. But the subrequest API (like +[ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture)), the [ngx.req.*](http://wiki.nginx.org/HttpLuaModule#ngx.req.start_time) API, the downstream output API +(like [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say), [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print), and [ngx.flush](http://wiki.nginx.org/HttpLuaModule#ngx.flush)) are explicitly disabled in +this context. + +This API was first introduced in the `v0.8.0` release. + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. @@ -4762,6 +4850,72 @@ Similarly, the following directives provided by [HttpEncryptedSessionModule](htt This feature requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. +coroutine.create +---------------- +**syntax:** *co = coroutine.create(f)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Creates a user Lua coroutines with a Lua function, and returns a coroutine object. + +Similar to the standard Lua [coroutine.create](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.create) API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the `v0.6.0` release. + +coroutine.resume +---------------- +**syntax:** *ok, ... = coroutine.resume(co, ...)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Resumes the executation of a user Lua coroutine object previously yielded or just created. + +Similar to the standard Lua [coroutine.resume](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.resume) API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the `v0.6.0` release. + +coroutine.yield +--------------- +**syntax:** *... = coroutine.yield(co, ...)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Yields the executation of the current user Lua coroutine. + +Similar to the standard Lua [coroutine.yield](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield) API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the `v0.6.0` release. + +coroutine.wrap +-------------- +**syntax:** *co = coroutine.wrap(f)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Similar to the standard Lua [coroutine.wrap](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap) API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the `v0.6.0` release. + +coroutine.running +----------------- +**syntax:** *co = coroutine.running()* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Identical to the standard Lua [coroutine.running](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running) API. + +This API was first enabled in the `v0.6.0` release. + +coroutine.status +---------------- +**syntax:** *status = coroutine.status(co)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** + +Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. + +This API was first enabled in the `v0.6.0` release. + Lua/LuaJIT bytecode support =========================== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 16bfec71fb..1d337a9a6c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -183,7 +183,7 @@ This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module = Description = -This module embeds Lua, via the standard Lua interpreter or [http://luajit.org/luajit.html LuaJIT 2.0], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. +This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. Unlike [http://httpd.apache.org/docs/2.3/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. @@ -1138,6 +1138,38 @@ This directive was first introduced in the v0.7.4 release. See also [[#ngx.on_abort|ngx.on_abort]]. +== lua_max_pending_timers == + +'''syntax:''' ''lua_max_pending_timers '' + +'''default:''' ''lua_max_pending_timers 1024'' + +'''context:''' ''http'' + +Controls the maximum number of pending timers allowed. + +Pending timers are those timers that have not expired yet. + +When exceeding this limit, the [[#ngx.timer.at|ngx.timer.at]] call will immediately return nil and the error string "too many pending timers". + +This directive was first introduced in the v0.8.0 release. + +== lua_max_running_timers == + +'''syntax:''' ''lua_max_running_timers '' + +'''default:''' ''lua_max_running_timers 256'' + +'''context:''' ''http'' + +Controls the maximum number of "running timers" allowed. + +Running timers are those timers whose user callback functions are still running. + +When exceeding this limit, Nginx will stop running the callbacks of newly expired timers and log an error message "N lua_max_running_timers are not enough" where "N" is the current value of this directive. + +This directive was first introduced in the v0.8.0 release. + = Nginx API for Lua = == Introduction == The various *_by_lua and *_by_lua_file configuration directives serve as gateways to the Lua API within the nginx.conf file. The Nginx Lua API described below can only be called within the user Lua code run in the context of these configuration directives. @@ -1250,7 +1282,7 @@ Setting ngx.var.Foo to a nil value will unset the ngx.OK (0) @@ -1271,7 +1303,7 @@ The ngx.null constant is a NULL light userdata usually The ngx.DECLINED constant was first introduced in the v0.5.0rc19 release. == HTTP method constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' ngx.HTTP_GET @@ -1285,7 +1317,7 @@ The ngx.DECLINED constant was first introduced in the v0.5.0r These constants are usually used in [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] method calls. == HTTP status constants == -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' value = ngx.HTTP_OK (200) @@ -1308,7 +1340,7 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.capture == Nginx log level constants == -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' ngx.STDERR @@ -1327,7 +1359,7 @@ These constants are usually used by the [[#ngx.log|ngx.log]] method. == print == '''syntax:''' ''print(...)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' Writes argument values into the nginx error.log file with the ngx.NOTICE log level. @@ -1342,7 +1374,7 @@ Lua nil arguments are accepted and result in literal "nil"2048 byte limitation on error message lengths in the Nginx core. This limit includes trailing newlines and leading time stamps. If the message size exceeds this limit, Nginx will truncate the message text accordingly. This limit can be manually modified by editing the NGX_MAX_ERROR_STR macro definition in the src/core/ngx_log.h file in the Nginx source tree. == ngx.ctx == -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*, ngx.timer.*'' This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). @@ -2754,7 +2786,7 @@ Just as [[#ngx.print|ngx.print]] but also emit a trailing newline. == ngx.log == '''syntax:''' ''ngx.log(log_level, ...)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Log arguments concatenated to error.log with the given logging level. @@ -2853,7 +2885,7 @@ But if you create subrequests to access other locations configured by Nginx upst == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one milliseconds). @@ -2866,14 +2898,14 @@ This method was introduced in the 0.5.0rc30 release. == ngx.escape_uri == '''syntax:''' ''newstr = ngx.escape_uri(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Escape str as a URI component. == ngx.unescape_uri == '''syntax:''' ''newstr = ngx.unescape_uri(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Unescape str as an escaped URI component. @@ -2892,7 +2924,7 @@ gives the output == ngx.encode_args == '''syntax:''' ''str = ngx.encode_args(table)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Encode the Lua table to a query args string according to the URI encoded rules. @@ -2943,7 +2975,7 @@ This method was first introduced in the v0.3.1rc27 release. == ngx.decode_args == '''syntax:''' ''table = ngx.decode_args(str, max_args?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Decodes a URI encoded query-string into a Lua table. This is the inverse function of [[#ngx.encode_args|ngx.encode_args]]. @@ -2962,21 +2994,21 @@ This method was introduced in the v0.5.0rc29. == ngx.encode_base64 == '''syntax:''' ''newstr = ngx.encode_base64(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Encode str to a base64 digest. == ngx.decode_base64 == '''syntax:''' ''newstr = ngx.decode_base64(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Decodes the str argument as a base64 digest to the raw form. Returns nil if str is not well formed. == ngx.crc32_short == '''syntax:''' ''intval = ngx.crc32_short(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -2989,7 +3021,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.crc32_long == '''syntax:''' ''intval = ngx.crc32_long(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Calculates the CRC-32 (Cyclic Redundancy Code) digest for the str argument. @@ -3002,7 +3034,7 @@ This API was first introduced in the v0.3.1rc8 release. == ngx.hmac_sha1 == '''syntax:''' ''digest = ngx.hmac_sha1(secret_key, str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Computes the [http://en.wikipedia.org/wiki/HMAC HMAC-SHA1] digest of the argument str and turns the result using the secret key . @@ -3030,7 +3062,7 @@ This function was first introduced in the v0.3.1rc29 release. == ngx.md5 == '''syntax:''' ''digest = ngx.md5(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the hexadecimal representation of the MD5 digest of the str argument. @@ -3053,7 +3085,7 @@ See [[#ngx.md5_bin|ngx.md5_bin]] if the raw binary MD5 digest is required. == ngx.md5_bin == '''syntax:''' ''digest = ngx.md5_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the binary form of the MD5 digest of the str argument. @@ -3062,7 +3094,7 @@ See [[#ngx.md5|ngx.md5]] if the hexadecimal form of the MD5 digest is required. == ngx.sha1_bin == '''syntax:''' ''digest = ngx.sha1_bin(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the binary form of the SHA-1 digest of the str argument. @@ -3073,14 +3105,14 @@ This function was first introduced in the v0.5.0rc6. == ngx.quote_sql_str == '''syntax:''' ''quoted_value = ngx.quote_sql_str(raw_value)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns a quoted SQL string literal according to the MySQL quoting rules. == ngx.today == '''syntax:''' ''str = ngx.today()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns current date (in the format yyyy-mm-dd) from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3089,7 +3121,7 @@ This is the local time. == ngx.time == '''syntax:''' ''secs = ngx.time()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3098,7 +3130,7 @@ Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.u == ngx.now == '''syntax:''' ''secs = ngx.now()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). @@ -3109,7 +3141,7 @@ This API was first introduced in v0.3.1rc32. == ngx.update_time == '''syntax:''' ''ngx.update_time()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Forcibly updates the Nginx current time cache. This call involves a syscall and thus has some overhead, so do not abuse it. @@ -3118,7 +3150,7 @@ This API was first introduced in v0.3.1rc32. == ngx.localtime == '''syntax:''' ''str = ngx.localtime()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -3127,7 +3159,7 @@ This is the local time. == ngx.utctime == '''syntax:''' ''str = ngx.utctime()'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns the current time stamp (in the format yyyy-mm-dd hh:mm:ss) of the nginx cached time (no syscall involved unlike Lua's [http://www.lua.org/manual/5.1/manual.html#pdf-os.date os.date] function). @@ -3136,7 +3168,7 @@ This is the UTC time. == ngx.cookie_time == '''syntax:''' ''str = ngx.cookie_time(sec)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns a formated string can be used as the cookie expiration time. The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -3148,7 +3180,7 @@ Returns a formated string can be used as the cookie expiration time. The paramet == ngx.http_time == '''syntax:''' ''str = ngx.http_time(sec)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Returns a formated string can be used as the http header time (for example, being used in Last-Modified header). The parameter sec is the time stamp in seconds (like those returned from [[#ngx.time|ngx.time]]). @@ -3160,7 +3192,7 @@ Returns a formated string can be used as the http header time (for example, bein == ngx.parse_http_time == '''syntax:''' ''sec = ngx.parse_http_time(str)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) into seconds. Returns the seconds or nil if the input string is in bad forms. @@ -3181,7 +3213,7 @@ Returns true if the current request is an nginx subrequest, or subject string using the Perl compatible regular expression regex with the optional options. @@ -3323,7 +3355,7 @@ This feature was introduced in the v0.2.1rc11 release. == ngx.re.gmatch == '''syntax:''' ''iterator, err = ngx.re.gmatch(subject, regex, options?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Similar to [[#ngx.re.match|ngx.re.match]], but returns a Lua iterator instead, so as to let the user programmer iterate all the matches over the string argument with the PCRE regex. @@ -3396,7 +3428,7 @@ This feature was first introduced in the v0.2.1rc12 release. == ngx.re.sub == '''syntax:''' ''newstr, n, err = ngx.re.sub(subject, regex, replace, options?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Substitutes the first match of the Perl compatible regular expression regex on the subject argument string with the string or function argument replace. The optional options argument has exactly the same meaning as in [[#ngx.re.match|ngx.re.match]]. @@ -3455,7 +3487,7 @@ This feature was first introduced in the v0.2.1rc13 release. == ngx.re.gsub == '''syntax:''' ''newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Just like [[#ngx.re.sub|ngx.re.sub]], but does global substitution. @@ -3488,7 +3520,7 @@ This feature was first introduced in the v0.2.1rc15 release. == ngx.shared.DICT == '''syntax:''' ''dict = ngx.shared.DICT'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. @@ -3552,7 +3584,7 @@ This feature was first introduced in the v0.3.1rc22 release. == ngx.shared.DICT.get == '''syntax:''' ''value, flags = ngx.shared.DICT:get(key)'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Retrieving the value in the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] for the key key. If the key does not exist or has been expired, then nil will be returned. @@ -3583,7 +3615,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.set == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Unconditionally sets a key-value pair into the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns three values: @@ -3626,7 +3658,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_set == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Similar to the [[#ngx.shared.DICT.set|set]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -3637,7 +3669,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.add == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key does ''not'' exist. @@ -3650,7 +3682,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.safe_add == '''syntax:''' ''ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Similar to the [[#ngx.shared.DICT.add|add]] method, but never overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone. In this case, it will immediately return nil and the string "no memory". @@ -3661,7 +3693,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.replace == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Just like the [[#ngx.shared.DICT.set|set]] method, but only stores the key-value pair into the dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] if the key ''does'' exist. @@ -3674,7 +3706,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.delete == '''syntax:''' ''ngx.shared.DICT:delete(key)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Unconditionally removes the key-value pair from the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -3687,7 +3719,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.incr == '''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Increments the (numerical) value for key in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] by the step value value. Returns the new resulting number if the operation is successfully completed or nil and an error message otherwise. @@ -3704,7 +3736,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Flushes out all the items in the dictionary. @@ -3715,7 +3747,7 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ == ngx.shared.DICT.flush_expired == '''syntax:''' ''flushed = ngx.shared.DICT:flush_expired(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. @@ -3726,7 +3758,7 @@ See also [[#ngx.shared.DICT.flush_all|ngx.shared.DICT.flush_all]] and [[#ngx.sha == ngx.shared.DICT.get_keys == '''syntax:''' ''keys = ngx.shared.DICT:get_keys(max_count?)'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Fetch a list of the keys from the dictionary, up to . @@ -3739,7 +3771,7 @@ This feature was first introduced in the v0.7.3 release. == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -3760,7 +3792,7 @@ See also [[#ngx.socket.tcp|ngx.socket.tcp]]. '''syntax:''' ''ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Attempts to connect a UDP socket object to a remote server or to a datagram unix domain socket file. Because the datagram protocol is actually connection-less, this method does not really establish a "connection", but only just set the name of the remote peer for subsequent read/write operations. @@ -3813,7 +3845,7 @@ This method was first introduced in the v0.5.7 release. == udpsock:send == '''syntax:''' ''ok, err = udpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Sends data on the current UDP or datagram unix domain socket object. @@ -3826,7 +3858,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:receive == '''syntax:''' ''data, err = udpsock:receive(size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Receives data from the UDP or datagram unix domain socket object with an optional receive buffer size argument, size. @@ -3857,7 +3889,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:close == '''syntax:''' ''ok, err = udpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Closes the current UDP or datagram unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -3868,7 +3900,7 @@ This feature was first introduced in the v0.5.7 release. == udpsock:settimeout == '''syntax:''' ''udpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Set the timeout value in milliseconds for subsequent socket operations (like [[#udpsock:receive|receive]]). @@ -3879,7 +3911,7 @@ This feature was first introduced in the v0.5.7 release. == ngx.socket.tcp == '''syntax:''' ''tcpsock = ngx.socket.tcp()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: @@ -3904,7 +3936,7 @@ See also [[#ngx.socket.udp|ngx.socket.udp]]. '''syntax:''' ''ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Attempts to connect a TCP socket object to a remote server or to a stream unix domain socket file without blocking. @@ -3976,7 +4008,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:send == '''syntax:''' ''bytes, err = tcpsock:send(data)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Sends data without blocking on the current TCP or Unix Domain Socket connection. @@ -4002,7 +4034,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''syntax:''' ''data, err, partial = tcpsock:receive(pattern?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Receives data from the connected socket according to the reading pattern or size. @@ -4038,7 +4070,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receiveuntil == '''syntax:''' ''iterator = tcpsock:receiveuntil(pattern, options?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' This method returns an iterator Lua function that can be called to read the data stream until it sees the specified pattern or an error occurs. @@ -4128,7 +4160,7 @@ This method was first introduced in the v0.5.0rc1 release. == tcpsock:close == '''syntax:''' ''ok, err = tcpsock:close()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Closes the current TCP or stream unix domain socket. It returns the 1 in case of success and returns nil with a string describing the error otherwise. @@ -4141,7 +4173,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:settimeout == '''syntax:''' ''tcpsock:settimeout(time)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Set the timeout value in milliseconds for subsequent socket operations ([[#tcpsock:connect|connect]], [[#tcpsock:receive|receive]], and iterators returned from [[#tcpsock:receiveuntil|receiveuntil]]). @@ -4154,7 +4186,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setoption == '''syntax:''' ''tcpsock:setoption(option, value?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' This function is added for [http://w3.impa.br/~diego/software/luasocket/tcp.html LuaSocket] API compatibility and does nothing for now. Its functionality will be implemented in future. @@ -4163,7 +4195,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:setkeepalive == '''syntax:''' ''ok, err = tcpsock:setkeepalive(timeout?, size?)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Puts the current socket's connection immediately into the cosocket built-in connection pool and keep it alive until other [[#tcpsock:connect|connect]] method calls request it or the associated maximal idle timeout is expired. @@ -4186,7 +4218,7 @@ This feature was first introduced in the v0.5.0rc1 release. == tcpsock:getreusedtimes == '''syntax:''' ''count, err = tcpsock:getreusedtimes()'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' This method returns the (successfully) reused times for the current connection. In case of error, it returns nil and a string describing the error. @@ -4199,7 +4231,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''syntax:''' ''tcpsock, err = ngx.socket.connect("unix:/path/to/unix-domain.socket")'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' This function is a shortcut for combining [[#ngx.socket.tcp|ngx.socket.tcp()]] and the [[#tcpsock:connect|connect()]] method call in a single operation. It is actually implemented like this: @@ -4219,7 +4251,7 @@ This feature was first introduced in the v0.5.0rc1 release. == ngx.get_phase == '''syntax:''' ''str = ngx.get_phase()'' -'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Retrieves the current running phase name. Possible return values are @@ -4239,73 +4271,15 @@ Retrieves the current running phase name. Possible return values are : for the context of [[#body_filter_by_lua|body_filter_by_lua]] or [[#body_filter_by_lua_file|body_filter_by_lua_file]]. * log : for the context of [[#log_by_lua|log_by_lua]] or [[#log_by_lua_file|log_by_lua_file]]. +* timer +: for the context of user callback functions for [[#ngx.timer.at|ngx.timer.*]]. This API was first introduced in the v0.5.10 release. -== coroutine.create == -'''syntax:''' ''co = coroutine.create(f)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Creates a user Lua coroutines with a Lua function, and returns a coroutine object. - -Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.create coroutine.create] API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the v0.6.0 release. - -== coroutine.resume == -'''syntax:''' ''ok, ... = coroutine.resume(co, ...)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Resumes the executation of a user Lua coroutine object previously yielded or just created. - -Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.resume coroutine.resume] API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the v0.6.0 release. - -== coroutine.yield == -'''syntax:''' ''... = coroutine.yield(co, ...)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Yields the executation of the current user Lua coroutine. - -Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield coroutine.yield] API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the v0.6.0 release. - -== coroutine.wrap == -'''syntax:''' ''co = coroutine.wrap(f)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap coroutine.wrap] API, but works in the context of the Lua coroutines created by ngx_lua. - -This API was first introduced in the v0.6.0 release. - -== coroutine.running == -'''syntax:''' ''co = coroutine.running()'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running coroutine.running] API. - -This API was first enabled in the v0.6.0 release. - -== coroutine.status == -'''syntax:''' ''status = coroutine.status(co)'' - -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' - -Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. - -This API was first enabled in the v0.6.0 release. - == ngx.thread.spawn == '''syntax:''' ''co = ngx.thread.spawn(func, arg1, arg2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Spawns a new user "light thread" with the Lua function func as well as those optional arguments arg1, arg2, and etc. Returns a Lua thread (or Lua coroutine) object represents this "light thread". @@ -4435,7 +4409,7 @@ This API was first enabled in the v0.7.0 release. == ngx.thread.wait == '''syntax:''' ''ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)'' -'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' Waits on one or more child "light threads" and returns the results of the first "light thread" that terminates (either successfully or with an error). @@ -4566,10 +4540,127 @@ This API was first introduced in the v0.7.4 release. See also [[#lua_check_client_abort|lua_check_client_abort]]. +== ngx.timer.at == +'''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' + +Creates an Nginx timer with a user callback function as well as optional user arguments. + +The first argument, delay, specifies the delay for the timer, +in seconds. One can specify fractional seconds like 0.001 to mean 1 +millisecond here. 0 delay can also be specified, in which case the +timer will immediately expire when the current handler yields +execution. + +The second argument, callback, can +be any Lua function, which will be invoked later in a background +"light thread" after the delay specified. The user callback will be +called automatically by the Nginx core with the arguments premature, +user_arg1, user_arg2, and etc, where the premature +argument takes a boolean value indicating whether it is a premature timer +expiration or not, and user_arg1, user_arg2, and etc, are +those (extra) user arguments specified when calling ngx.timer.at +as the remaining arguments. + +Premature timer expiration happens when the Nginx worker process is +trying to shut down, as in an Nginx configuration reload triggered by +the HUP signal or in an Nginx server shutdown. When the Nginx worker +is trying to shut down, one can no longer call ngx.timer.at to +create new timers and in that case ngx.timer.at will return nil and +a string describing the error, that is, "process exiting". + +When a timer expires, the user Lua code in the timer callback is +running in a "light thread" detached completely from the original +request creating the timer. So objects with the same lifetime as the +request creating them, like [[#ngx.socket.tcp|cosockets]], cannot be shared between the +original request and the timer user callback function. + +Here is a simple example: + + + location / { + ... + log_by_lua ' + local function push_data(premature, uri, args, status) + -- push the data uri, args, and status to the remote + -- via ngx.socket.tcp or ngx.socket.udp + -- (one may want to buffer the data in Lua a bit to + -- save I/O operations) + end + local ok, err = ngx.timer.at(0, push_data, + ngx.var.uri, ngx.var.args, ngx.header.status) + if not ok then + ngx.log(ngx.ERR, "failed to create timer: ", err) + return + end + '; + } + + +One can also create infinite re-occuring timers, for instance, a timer getting triggered every 5 seconds, by calling ngx.timer.at recursively in the timer callback function. Here is such an example, + + + local delay = 5 + local handler + handler = function (premature) + -- do some routine job in Lua just like a cron job + if premature then + return + end + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + end + + local ok, err = ngx.timer.at(delay, handler) + if not ok then + ngx.log(ngx.ERR, "failed to create the timer: ", err) + return + end + + +Because timer callbacks run in the background and their running time +will not add to any client request's response time, they can easily +accumulate in the server and exhaust system resources due to either +Lua programming mistakes or just too much client traffic. To prevent +extreme consequences like crashing the Nginx server, there are +built-in limitations on both the number of "pending timers" and the +number of "running timers" in an Nginx worker process. The "pending +timers" here mean timers that have not yet been expired and "running +timers" are those whose user callbacks are currently running. + +The maximal number of pending timers allowed in an Nginx +worker is constrolled by the [[#lua_max_pending_timers|lua_max_pending_timers]] +directive. The maximal number of running timers is controlled by the +[[#lua_max_running_timers|lua_max_running_timers]] directive. + +According to the current implementation, each "running timer" will +take one (fake) connection record from the global connection record +list configured by the standard [[EventsModule#worker_connections|worker_connections]] directive in +nginx.conf. So ensure that the +[[EventsModule#worker_connections|worker_connections]] directive is set to +a large enough value that takes into account both the real connections +and fake connections required by timer callbacks (as limited by the +[[#lua_max_running_timers|lua_max_running_timers]] directive). + +A lot of the Lua APIs for Nginx are enabled in the context of the timer +callbacks, like stream/datagram cosockets ([[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.socket.udp|ngx.socket.udp]]), shared +memory dictionaries ([[#ngx.shared.DICT|ngx.shared.DICT]]), user coroutines ([[#coroutine.create|coroutine.*]]), +user "light threads" ([[#ngx.thread.spawn|ngx.thread.*]]), [[#ngx.exit|ngx.exit]], [[#ngx.now|ngx.now]]/[[#ngx.time|ngx.time]], +[[#ngx.md5|ngx.md5]]/[[#ngx.sha1|ngx.sha1]], are all allowed. But the subrequest API (like +[[#ngx.location.capture|ngx.location.capture]]), the [[#ngx.req.start_time|ngx.req.*]] API, the downstream output API +(like [[#ngx.say|ngx.say]], [[#ngx.print|ngx.print]], and [[#ngx.flush|ngx.flush]]) are explicitly disabled in +this context. + +This API was first introduced in the v0.8.0 release. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*'' +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' This mechanism allows calling other nginx C modules' directives that are implemented by [https://github.com/simpl/ngx_devel_kit Nginx Devel Kit] (NDK)'s set_var submodule's ndk_set_var_value. @@ -4603,6 +4694,66 @@ Similarly, the following directives provided by [[HttpEncryptedSessionModule]] c This feature requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module. +== coroutine.create == +'''syntax:''' ''co = coroutine.create(f)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Creates a user Lua coroutines with a Lua function, and returns a coroutine object. + +Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.create coroutine.create] API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the v0.6.0 release. + +== coroutine.resume == +'''syntax:''' ''ok, ... = coroutine.resume(co, ...)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Resumes the executation of a user Lua coroutine object previously yielded or just created. + +Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.resume coroutine.resume] API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the v0.6.0 release. + +== coroutine.yield == +'''syntax:''' ''... = coroutine.yield(co, ...)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Yields the executation of the current user Lua coroutine. + +Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.yield coroutine.yield] API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the v0.6.0 release. + +== coroutine.wrap == +'''syntax:''' ''co = coroutine.wrap(f)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Similar to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.wrap coroutine.wrap] API, but works in the context of the Lua coroutines created by ngx_lua. + +This API was first introduced in the v0.6.0 release. + +== coroutine.running == +'''syntax:''' ''co = coroutine.running()'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.running coroutine.running] API. + +This API was first enabled in the v0.6.0 release. + +== coroutine.status == +'''syntax:''' ''status = coroutine.status(co)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*'' + +Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. + +This API was first enabled in the v0.6.0 release. + = Lua/LuaJIT bytecode support = As from the v0.5.0rc32 release, all *_by_lua_file configure directives (such as [[#content_by_lua_file|content_by_lua_file]]) support loading Lua 5.1 and LuaJIT 2.0 raw bytecode files directly. From 2aa12ab3dff506c8fa300df75e33fba4367509d4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 12:29:14 -0700 Subject: [PATCH 0077/1981] bumped version to 0.8.0. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index c3565bfdde..1563336b5e 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.21 - () released on 16 + This document describes ngx_lua v0.8.0 + () released on 23 April 2013. Synopsis diff --git a/README.markdown b/README.markdown index adc2c67fd3..b7d8d691e9 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.7.21](https://github.com/chaoslawful/lua-nginx-module/tags) released on 16 April 2013. +This document describes ngx_lua [v0.8.0](https://github.com/chaoslawful/lua-nginx-module/tags) released on 23 April 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 1d337a9a6c..187a6ec089 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.21] released on 16 April 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.0] released on 23 April 2013. = Synopsis = From 55555a78a0faa2ef2887708213807877fcd0bf51 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 18:07:58 -0700 Subject: [PATCH 0078/1981] bugfix: modifying the User-Agent request header via ngx.req.set_header or ngx.req.clear_header did not update those special internal flags in the Nginx core, like "r->headers_in.msie6" and "r->headers_in.opera". Thanks Matthieu Tourne for the patch. --- src/ngx_http_lua_headers_in.c | 79 +++- t/111-req-header-ua.t | 677 ++++++++++++++++++++++++++++++++++ 2 files changed, 755 insertions(+), 1 deletion(-) create mode 100644 t/111-req-header-ua.t diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 9dd5a83d3c..f4413b6081 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -23,6 +23,8 @@ static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, ngx_table_elt_t **output_header, unsigned no_create); static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, @@ -57,7 +59,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), - ngx_http_set_builtin_header }, + ngx_http_set_user_agent_header }, { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), @@ -266,6 +268,81 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, } +/* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */ +static ngx_int_t +ngx_http_set_user_agent_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value) +{ + u_char *user_agent, *msie; + + /* clear existing settings */ + + r->headers_in.msie = 0; + r->headers_in.msie6 = 0; + r->headers_in.opera = 0; + r->headers_in.gecko = 0; + r->headers_in.chrome = 0; + r->headers_in.safari = 0; + r->headers_in.konqueror = 0; + + if (value->len == 0) { + return ngx_http_set_builtin_header(r, hv, value); + } + + /* check some widespread browsers */ + + user_agent = value->data; + + msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); + + if (msie && msie + 7 < user_agent + value->len) { + + r->headers_in.msie = 1; + + if (msie[6] == '.') { + + switch (msie[5]) { + case '4': + case '5': + r->headers_in.msie6 = 1; + break; + case '6': + if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { + r->headers_in.msie6 = 1; + } + break; + } + } + } + + if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { + r->headers_in.opera = 1; + r->headers_in.msie = 0; + r->headers_in.msie6 = 0; + } + + if (!r->headers_in.msie && !r->headers_in.opera) { + + if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { + r->headers_in.gecko = 1; + + } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { + r->headers_in.chrome = 1; + + } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1) + && ngx_strstrn(user_agent, "Mac OS X", 8 - 1)) + { + r->headers_in.safari = 1; + + } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { + r->headers_in.konqueror = 1; + } + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) diff --git a/t/111-req-header-ua.t b/t/111-req-header-ua.t new file mode 100644 index 0000000000..4b1d39c4e6 --- /dev/null +++ b/t/111-req-header-ua.t @@ -0,0 +1,677 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear Opera user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.7.4; U; en) Presto/2.10.229 Version/11.62 + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: opera: %d\n", $r->headers_in->opera) +} + + +F(ngx_http_core_content_phase) { + printf("content: opera: %d\n", $r->headers_in->opera) +} + +--- stap_out +rewrite: opera: 1 +content: opera: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 2: clear MSIE 4 user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 3: set custom MSIE 4 user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0) +--- no_error_log +[error] + + + +=== TEST 4: clear MSIE 5 user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 5: set custom MSIE 5 user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSIECrawler) +--- no_error_log +[error] + + + +=== TEST 6: clear MSIE 6 (without SV1) user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=1 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 7: set custom MSIE 6 (without SV1) user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=1 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;) +--- no_error_log +[error] + + + +=== TEST 8: clear MSIE 6 (with SV1) user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=1 msie6=0 +content: msie=0 msie6=0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 9: set custom MSIE 6 (with SV1) user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=0 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1) +--- no_error_log +[error] + + + +=== TEST 10: set custom MSIE 7 user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +F(ngx_http_core_content_phase) { + printf("content: msie=%d msie6=%d\n", + $r->headers_in->msie, + $r->headers_in->msie6) +} + +--- stap_out +rewrite: msie=0 msie6=0 +content: msie=1 msie6=0 + +--- response_body +User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; winfx; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Zune 2.0) +--- no_error_log +[error] + + + +=== TEST 11: clear Gecko user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: gecko: %d\n", $r->headers_in->gecko) +} + + +F(ngx_http_core_content_phase) { + printf("content: gecko: %d\n", $r->headers_in->gecko) +} + +--- stap_out +rewrite: gecko: 1 +content: gecko: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 12: set custom Gecko user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0") + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: gecko: %d\n", $r->headers_in->gecko) +} + + +F(ngx_http_core_content_phase) { + printf("content: gecko: %d\n", $r->headers_in->gecko) +} + +--- stap_out +rewrite: gecko: 0 +content: gecko: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 +--- no_error_log +[error] + + + +=== TEST 13: clear Chrome user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: chrome: %d\n", $r->headers_in->chrome) +} + + +F(ngx_http_core_content_phase) { + printf("content: chrome: %d\n", $r->headers_in->chrome) +} + +--- stap_out +rewrite: chrome: 1 +content: chrome: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 14: set custom Chrome user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19") + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: chrome: %d\n", $r->headers_in->chrome) +} + + +F(ngx_http_core_content_phase) { + printf("content: chrome: %d\n", $r->headers_in->chrome) +} + +--- stap_out +rewrite: chrome: 0 +content: chrome: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19 +--- no_error_log +[error] + + + +=== TEST 15: clear Safari (Mac OS X) user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: safari: %d\n", $r->headers_in->safari) +} + + +F(ngx_http_core_content_phase) { + printf("content: safari: %d\n", $r->headers_in->safari) +} + +--- stap_out +rewrite: safari: 1 +content: safari: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 16: set custom Safari user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: safari: %d\n", $r->headers_in->safari) +} + + +F(ngx_http_core_content_phase) { + printf("content: safari: %d\n", $r->headers_in->safari) +} + +--- stap_out +rewrite: safari: 0 +content: safari: 1 + +--- response_body +User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +--- no_error_log +[error] + + + +=== TEST 17: clear Konqueror user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", nil) + + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- more_headers +User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) +} + + +F(ngx_http_core_content_phase) { + printf("content: konqueror: %d\n", $r->headers_in->konqueror) +} + +--- stap_out +rewrite: konqueror: 1 +content: konqueror: 0 + +--- response_body +User-Agent: +--- no_error_log +[error] + + + +=== TEST 18: set custom Konqueror user-agent +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("User-Agent", "Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu)") + '; + echo "User-Agent: $http_user_agent"; + } + +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: konqueror: %d\n", $r->headers_in->konqueror) +} + + +F(ngx_http_core_content_phase) { + printf("content: konqueror: %d\n", $r->headers_in->konqueror) +} + +--- stap_out +rewrite: konqueror: 0 +content: konqueror: 1 + +--- response_body +User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) +--- no_error_log +[error] + From a07df6151a03ec99c7aa0439e7bba93464ed6249 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 19:05:15 -0700 Subject: [PATCH 0079/1981] bugfix: modifying the Connection request header via ngx.req.set_header or ngx.req.clear_header did not update the special internal flags in the Nginx core, "r->headers_in.connection_type" and "r->headers_in.keep_alive_n". Thanks Matthieu Tourne for the patch. --- src/ngx_http_lua_headers_in.c | 26 +++++- t/112-req-header-conn.t | 150 ++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 t/112-req-header-conn.t diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index f4413b6081..bd4af76078 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -25,6 +25,8 @@ static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, @@ -51,7 +53,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), - ngx_http_set_builtin_header }, + ngx_http_set_connection_header }, { ngx_string("If-Modified-Since"), offsetof(ngx_http_headers_in_t, if_modified_since), @@ -268,6 +270,28 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, } +static ngx_int_t +ngx_http_set_connection_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value) +{ + r->headers_in.connection_type = 0; + + if (value->len == 0) { + return ngx_http_set_builtin_header(r, hv, value); + } + + if (ngx_strcasestrn(value->data, "close", 5 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; + r->headers_in.keep_alive_n = -1; + + } else if (ngx_strcasestrn(value->data, "keep-alive", 10 - 1)) { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; + } + + return ngx_http_set_builtin_header(r, hv, value); +} + + /* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */ static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, diff --git a/t/112-req-header-conn.t b/t/112-req-header-conn.t new file mode 100644 index 0000000000..37f1a2e435 --- /dev/null +++ b/t/112-req-header-conn.t @@ -0,0 +1,150 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear the Connection req header +--- config + location /req-header { + rewrite_by_lua ' + ngx.req.set_header("Connection", nil); + '; + + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 0 + +--- response_body +connection: +--- no_error_log +[error] + + + +=== TEST 2: set custom Connection req header (close) +--- config + location /req-header { + rewrite_by_lua ' + ngx.req.set_header("Connection", "CLOSE"); + '; + + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 1 + +--- response_body +connection: CLOSE +--- no_error_log +[error] + + + +=== TEST 3: set custom Connection req header (keep-alive) +--- config + location /req-header { + rewrite_by_lua ' + ngx.req.set_header("Connection", "keep-alive"); + '; + + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 2 + +--- response_body +connection: keep-alive +--- no_error_log +[error] + + + +=== TEST 4: set custom Connection req header (bad) +--- config + location /req-header { + rewrite_by_lua ' + ngx.req.set_header("Connection", "bad"); + '; + + echo "connection: $http_connection"; + } +--- request +GET /req-header + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) +} + + +F(ngx_http_core_content_phase) { + printf("content: conn type: %d\n", $r->headers_in->connection_type) +} + +--- stap_out +rewrite: conn type: 1 +content: conn type: 0 + +--- response_body +connection: bad +--- no_error_log +[error] + From 97425f8dc6963e4055ac43cebd730df3bfe676a4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 20:31:26 -0700 Subject: [PATCH 0080/1981] bugfix: ngx.req.set_header/ngx.req.clear_header did not update the special field r->headers_in.x_real_ip when the ngx_realip module was enabled. thanks Matthieu Tourne for the patch. --- src/ngx_http_lua_headers_in.c | 6 +++ t/028-req-header.t | 93 ++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index bd4af76078..2e9c0cd3e5 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -99,6 +99,12 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, content_length), ngx_http_set_content_length_header }, +#if (NGX_HTTP_REALIP) + { ngx_string("X-Real-IP"), + offsetof(ngx_http_headers_in_t, x_real_ip), + ngx_http_set_builtin_header }, +#endif + { ngx_null_string, 0, ngx_http_set_header } }; diff --git a/t/028-req-header.t b/t/028-req-header.t index b02c19f089..2bdcdbf6a6 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => (2 * blocks() + 6) * repeat_each(); +plan tests => repeat_each() * (2 * blocks() + 10); #no_diff(); no_long_string(); @@ -1064,3 +1064,94 @@ Connection: Close --- no_error_log [error] + + +=== TEST 35: clear X-Real-IP +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("X-Real-IP", nil) + '; + echo "X-Real-IP: $http_x_real_ip"; + } +--- request +GET /t +--- more_headers +X-Real-IP: 8.8.8.8 + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("rewrite: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("rewrite: no x-real-ip") + } +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("content: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("content: no x-real-ip") + } +} + +--- stap_out +rewrite: x-real-ip: 8.8.8.8 +content: no x-real-ip + +--- response_body +X-Real-IP: + +--- no_error_log +[error] + + + +=== TEST 36: set custom X-Real-IP +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("X-Real-IP", "8.8.4.4") + '; + echo "X-Real-IP: $http_x_real_ip"; + } +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("rewrite: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("rewrite: no x-real-ip") + } + +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->x_real_ip) && $r->headers_in->x_real_ip) { + printf("content: x-real-ip: %s\n", + user_string_n($r->headers_in->x_real_ip->value->data, + $r->headers_in->x_real_ip->value->len)) + } else { + println("content: no x-real-ip") + } +} + +--- stap_out +rewrite: no x-real-ip +content: x-real-ip: 8.8.4.4 + +--- response_body +X-Real-IP: 8.8.4.4 + +--- no_error_log +[error] + From b90e7dd1ab93d68499d17520b4c88c91c2914b71 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 20:43:32 -0700 Subject: [PATCH 0081/1981] bugfix: modifying the Via request header with ngx.req.set_header/ngx.req.clear_header did not update the special field r->headers_in.via when the ngx_gzip module was enabled. --- src/ngx_http_lua_headers_in.c | 4 ++ t/028-req-header.t | 93 ++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 2e9c0cd3e5..629aa3e8a3 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -45,6 +45,10 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("Accept-Encoding"), offsetof(ngx_http_headers_in_t, accept_encoding), ngx_http_set_builtin_header }, + + { ngx_string("Via"), + offsetof(ngx_http_headers_in_t, via), + ngx_http_set_builtin_header }, #endif { ngx_string("Host"), diff --git a/t/028-req-header.t b/t/028-req-header.t index 2bdcdbf6a6..76604efcf4 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 10); +plan tests => repeat_each() * (2 * blocks() + 14); #no_diff(); no_long_string(); @@ -1155,3 +1155,94 @@ X-Real-IP: 8.8.4.4 --- no_error_log [error] + + +=== TEST 37: clear Via +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Via", nil) + '; + echo "Via: $http_via"; + } +--- request +GET /t +--- more_headers +Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("rewrite: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("rewrite: no via") + } +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("content: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("content: no via") + } +} + +--- stap_out +rewrite: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) +content: no via + +--- response_body +Via: + +--- no_error_log +[error] + + + +=== TEST 38: set custom Via +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Via", "1.0 fred, 1.1 nowhere.com (Apache/1.1)") + '; + echo "Via: $http_via"; + } +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("rewrite: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("rewrite: no via") + } + +} + +F(ngx_http_core_content_phase) { + if (@defined($r->headers_in->via) && $r->headers_in->via) { + printf("content: via: %s\n", + user_string_n($r->headers_in->via->value->data, + $r->headers_in->via->value->len)) + } else { + println("content: no via") + } +} + +--- stap_out +rewrite: no via +content: via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- response_body +Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + +--- no_error_log +[error] + From 766563fba3eb47150827d0ed465d8b3663b1024f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 21:58:10 -0700 Subject: [PATCH 0082/1981] one minor coding style fix. --- src/ngx_http_lua_headers_in.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 629aa3e8a3..9987e54b39 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -434,7 +434,7 @@ ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, hv.key = key; hv.offset = 0; - hv.no_override = ! override; + hv.no_override = !override; hv.handler = NULL; for (i = 0; handlers[i].name.len; i++) { From 0ac676f65413c1f05c54bbdce52b0336cdf024a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 23 Apr 2013 22:19:22 -0700 Subject: [PATCH 0083/1981] feature: added the "U" regex option to the ngx.re API to mean enabling the UTF-8 matching mode but disabling UTF-8 validity check on the subject strings. thanks Lance Li for the patch in #227. --- src/ngx_http_lua_regex.c | 52 +++++++++++++++++++++++------ t/034-match.t | 70 +++++++++++++++++++++++++++++++++++++- t/035-gmatch.t | 72 +++++++++++++++++++++++++++++++++++++++- t/036-sub.t | 66 +++++++++++++++++++++++++++++++++++- t/037-gsub.t | 70 +++++++++++++++++++++++++++++++++++++- t/048-match-dfa.t | 70 +++++++++++++++++++++++++++++++++++++- t/050-gmatch-dfa.t | 72 +++++++++++++++++++++++++++++++++++++++- t/052-sub-dfa.t | 66 +++++++++++++++++++++++++++++++++++- t/054-gsub-dfa.t | 70 +++++++++++++++++++++++++++++++++++++- 9 files changed, 590 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 63f0a1ac59..0ae60bc338 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -38,6 +38,7 @@ #define NGX_LUA_RE_MODE_DFA (1<<1) #define NGX_LUA_RE_MODE_JIT (1<<2) #define NGX_LUA_RE_MODE_DUPNAMES (1<<3) +#define NGX_LUA_RE_NO_UTF8_CHECK (1<<4) #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100) @@ -93,14 +94,14 @@ static void ngx_http_lua_re_collect_named_captures(lua_State *L, unsigned flags, ngx_str_t *subj); -#define ngx_http_lua_regex_exec(re, e, s, start, captures, size) \ - pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, 0, \ +#define ngx_http_lua_regex_exec(re, e, s, start, captures, size, opts) \ + pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \ captures, size) #define ngx_http_lua_regex_dfa_exec(re, e, s, start, captures, size, ws, \ - wscount) \ - pcre_dfa_exec(re, e, (const char *) (s)->data, (s)->len, start, 0, \ + wscount, opts) \ + pcre_dfa_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \ captures, size, ws, wscount) @@ -128,6 +129,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) pcre_extra *sd = NULL; int name_entry_size, name_count; u_char *name_table; + int exec_opts; ngx_http_lua_regex_compile_t re_comp; @@ -429,6 +431,13 @@ ngx_http_lua_ngx_re_match(lua_State *L) } } + if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { + exec_opts = PCRE_NO_UTF8_CHECK; + + } else { + exec_opts = 0; + } + if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA @@ -436,7 +445,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj, (int) pos, cap, ovecsize, ws, - sizeof(ws)/sizeof(ws[0])); + sizeof(ws)/sizeof(ws[0]), exec_opts); #else /* LUA_HAVE_PCRE_DFA */ @@ -447,7 +456,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) } else { rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, (int) pos, cap, - ovecsize); + ovecsize, exec_opts); } if (rc == NGX_REGEX_NO_MATCHED) { @@ -894,6 +903,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) const char *msg = NULL; int name_entry_size, name_count; u_char *name_table; + int exec_opts; /* upvalues in order: subj ctx offset */ @@ -949,6 +959,13 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) } } + if (ctx->flags & NGX_LUA_RE_NO_UTF8_CHECK) { + exec_opts = PCRE_NO_UTF8_CHECK; + + } else { + exec_opts = 0; + } + if (ctx->flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA @@ -957,7 +974,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) rc = ngx_http_lua_regex_dfa_exec(ctx->regex, ctx->regex_sd, &subj, offset, cap, ctx->captures_len, ws, - sizeof(ws)/sizeof(ws[0])); + sizeof(ws)/sizeof(ws[0]), exec_opts); #else /* LUA_HAVE_PCRE_DFA */ msg = "at least pcre 6.0 is required for the DFA mode"; @@ -967,7 +984,8 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) } else { rc = ngx_http_lua_regex_exec(ctx->regex, ctx->regex_sd, &subj, - offset, cap, ctx->captures_len); + offset, cap, ctx->captures_len, + exec_opts); } if (rc == NGX_REGEX_NO_MATCHED) { @@ -1099,6 +1117,11 @@ ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_http_lua_regex_compile_t *re, re->options |= PCRE_UTF8; break; + case 'U': + re->options |= PCRE_UTF8; + flags |= NGX_LUA_RE_NO_UTF8_CHECK; + break; + case 'x': re->options |= PCRE_EXTENDED; break; @@ -1193,6 +1216,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) pcre_extra *sd = NULL; int name_entry_size, name_count; u_char *name_table; + int exec_opts; ngx_http_lua_regex_compile_t re_comp; ngx_http_lua_complex_value_t *ctpl = NULL; @@ -1572,6 +1596,13 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } } + if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { + exec_opts = PCRE_NO_UTF8_CHECK; + + } else { + exec_opts = 0; + } + for (;;) { if (flags & NGX_LUA_RE_MODE_DFA) { @@ -1580,7 +1611,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj, offset, cap, ovecsize, ws, - sizeof(ws)/sizeof(ws[0])); + sizeof(ws)/sizeof(ws[0]), + exec_opts); #else /* LUA_HAVE_PCRE_DFA */ @@ -1591,7 +1623,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } else { rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, offset, cap, - ovecsize); + ovecsize, exec_opts); } if (rc == NGX_REGEX_NO_MATCHED) { diff --git a/t/034-match.t b/t/034-match.t index 6efefe787d..c76c520b2f 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 10); +plan tests => repeat_each() * (blocks() * 2 + 14); #no_diff(); no_long_string(); @@ -945,3 +945,71 @@ error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" --- no_error_log [error] + + +=== TEST 43: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("你好", ".", "U") + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + + + +=== TEST 44: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("你好", ".", "u") + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 2661cdfb93..a5c7c82681 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(5); -plan tests => repeat_each() * (blocks() * 2 + 3); +plan tests => repeat_each() * (blocks() * 2 + 7); our $HtmlDir = html_dir; @@ -741,3 +741,73 @@ error: pcre_exec\(\) failed: -10 on "你.*?" --- no_error_log [error] + + +=== TEST 28: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("你好", ".", "U") + local m = it() + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + + + +=== TEST 29: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("你好", ".", "u") + local m = it() + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + diff --git a/t/036-sub.t b/t/036-sub.t index 43f883028e..18d2715a95 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 9); +plan tests => repeat_each() * (blocks() * 2 + 13); #no_diff(); no_long_string(); @@ -507,3 +507,67 @@ error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" --- no_error_log [error] + + +=== TEST 26: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.sub("你好", ".", "a", "U") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +s: a好 +--- no_error_log +[error] + + + +=== TEST 27: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.sub("你好", ".", "a", "u") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +s: a好 +--- no_error_log +[error] + diff --git a/t/037-gsub.t b/t/037-gsub.t index 9a26390f53..31b97e63ae 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 10); +plan tests => repeat_each() * (blocks() * 2 + 14); #no_diff(); no_long_string(); @@ -430,3 +430,71 @@ error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" --- no_error_log [error] + + +=== TEST 21: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.gsub("你好", ".", "a", "U") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 +exec opts: 2000 +exec opts: 2000 + +--- request + GET /re +--- response_body +s: aa +--- no_error_log +[error] + + + +=== TEST 22: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.gsub("你好", ".", "a", "u") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 +exec opts: 0 +exec opts: 0 + +--- request + GET /re +--- response_body +s: aa +--- no_error_log +[error] + diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t index 31ecb6e972..a29c20343f 100644 --- a/t/048-match-dfa.t +++ b/t/048-match-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); no_long_string(); @@ -114,3 +114,71 @@ nil --- response_body not matched! + + +=== TEST 6: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("你好", ".", "Ud") + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + + + +=== TEST 7: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("你好", ".", "ud") + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index 28492763bc..a8a97d5171 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); #no_long_string(); @@ -217,3 +217,73 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- no_error_log [error] + + +=== TEST 11: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("你好", ".", "Ud") + local m = it() + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + + + +=== TEST 12: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("你好", ".", "ud") + local m = it() + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +你 +--- no_error_log +[error] + diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index 62e3b07bde..23418634f4 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); no_long_string(); @@ -135,3 +135,67 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- no_error_log [error] + + +=== TEST 7: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.sub("你好", ".", "a", "Ud") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 + +--- request + GET /re +--- response_body +s: a好 +--- no_error_log +[error] + + + +=== TEST 8: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.sub("你好", ".", "a", "ud") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 + +--- request + GET /re +--- response_body +s: a好 +--- no_error_log +[error] + diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index 21f55a3fa0..a4527267f8 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); no_long_string(); @@ -132,3 +132,71 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- no_error_log [error] + + +=== TEST 7: UTF-8 mode without UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.gsub("你好", ".", "a", "Ud") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 2000 +exec opts: 2000 +exec opts: 2000 + +--- request + GET /re +--- response_body +s: aa +--- no_error_log +[error] + + + +=== TEST 8: UTF-8 mode with UTF-8 sequence checks +--- config + location /re { + content_by_lua ' + local s, n, err = ngx.re.gsub("你好", ".", "a", "ud") + if s then + ngx.say("s: ", s) + end + '; + } +--- stap +probe process("$LIBPCRE_PATH").function("pcre_compile") { + printf("compile opts: %x\n", $options) +} + +probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { + printf("exec opts: %x\n", $options) +} + +--- stap_out +compile opts: 800 +exec opts: 0 +exec opts: 0 +exec opts: 0 + +--- request + GET /re +--- response_body +s: aa +--- no_error_log +[error] + From 7e515f189ee6d10e30291e351b9a7ce1879597c5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 16:13:58 -0700 Subject: [PATCH 0084/1981] bugfix: modifying the Cookie request headers via ngx.req.set_header or ngx.req.clear_header did not update the Nginx internal data structure, r->headers_in.cookies, at the same time, which might cause issues when reading variables $cookie_COOKIE, for example. thanks Matthieu Tourne for the patch. --- src/ngx_http_lua_headers_in.c | 45 ++++++ t/113-req-header-cookie.t | 251 ++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 t/113-req-header-cookie.t diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 9987e54b39..8391de00da 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -29,6 +29,8 @@ static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_cookie_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, @@ -103,6 +105,10 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, content_length), ngx_http_set_content_length_header }, + { ngx_string("Cookie"), + 0, + ngx_http_set_cookie_header }, + #if (NGX_HTTP_REALIP) { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip), @@ -400,6 +406,45 @@ ngx_http_set_content_length_header(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_set_cookie_header(ngx_http_request_t *r, + ngx_http_lua_header_val_t *hv, ngx_str_t *value) +{ + ngx_table_elt_t **cookie, *h; + + if (!hv->no_override && r->headers_in.cookies.nelts > 0) { + ngx_array_destroy(&r->headers_in.cookies); + + if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, + sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + + dd("clear headers in cookies: %d", (int) r->headers_in.cookies.nelts); + } + + if (ngx_http_set_header_helper(r, hv, value, &h, 0) == NGX_ERROR) { + return NGX_ERROR; + } + + if (value->len == 0) { + return NGX_OK; + } + + dd("new cookie header: %p", h); + + cookie = ngx_array_push(&r->headers_in.cookies); + if (cookie == NULL) { + return NGX_ERROR; + } + + *cookie = h; + return NGX_OK; +} + + static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t new file mode 100644 index 0000000000..526586073d --- /dev/null +++ b/t/113-req-header-cookie.t @@ -0,0 +1,251 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (4 * blocks()); + +#no_diff(); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: clear cookie (with existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", nil) + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t +--- more_headers +Cookie: foo=bar +Cookie: baz=blah + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 2 +content: cookies: 0 + +--- response_body +Cookie foo: +Cookie baz: +Cookie: + +--- no_error_log +[error] + + + +=== TEST 2: clear cookie (without existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", nil) + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 0 +content: cookies: 0 + +--- response_body +Cookie foo: +Cookie baz: +Cookie: + +--- no_error_log +[error] + + + +=== TEST 3: set one custom cookie (with existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", "boo=123") + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t +--- more_headers +Cookie: foo=bar +Cookie: baz=blah + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 2 +content: cookies: 1 + +--- response_body +Cookie foo: +Cookie baz: +Cookie boo: 123 +Cookie: boo=123 + +--- no_error_log +[error] + + + +=== TEST 4: set one custom cookie (without existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", "boo=123") + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 0 +content: cookies: 1 + +--- response_body +Cookie foo: +Cookie baz: +Cookie boo: 123 +Cookie: boo=123 + +--- no_error_log +[error] + + + +=== TEST 5: set multiple custom cookies (with existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", {"boo=123","foo=78"}) + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t +--- more_headers +Cookie: foo=bar +Cookie: baz=blah + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 2 +content: cookies: 2 + +--- response_body +Cookie foo: 78 +Cookie baz: +Cookie boo: 123 +Cookie: boo=123; foo=78 + +--- no_error_log +[error] + + + +=== TEST 6: set one custom cookie (without existing cookies) +--- config + location /t { + rewrite_by_lua ' + ngx.req.set_header("Cookie", {"boo=123", "foo=bar"}) + '; + echo "Cookie foo: $cookie_foo"; + echo "Cookie baz: $cookie_baz"; + echo "Cookie boo: $cookie_boo"; + echo "Cookie: $http_cookie"; + } +--- request +GET /t + +--- stap +F(ngx_http_lua_rewrite_by_chunk) { + printf("rewrite: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +F(ngx_http_core_content_phase) { + printf("content: cookies: %d\n", $r->headers_in->cookies->nelts) +} + +--- stap_out +rewrite: cookies: 0 +content: cookies: 2 + +--- response_body +Cookie foo: bar +Cookie baz: +Cookie boo: 123 +Cookie: boo=123; foo=bar + +--- no_error_log +[error] + From 7695a31e045cdc3999a957e04291c7063c60931d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 16:29:12 -0700 Subject: [PATCH 0085/1981] documented the new "U" regex option for the ngx.re API. --- README | 3 +++ README.markdown | 3 +++ doc/HttpLuaModule.wiki | 3 +++ 3 files changed, 9 insertions(+) diff --git a/README b/README index 1563336b5e..5b3b4d86f3 100644 --- a/README +++ b/README @@ -3689,6 +3689,9 @@ Nginx API for Lua u UTF-8 mode. this requires PCRE to be built with the --enable-utf8 option or else a Lua exception will be thrown. + U similar to "u" but disables PCRE's UTF-8 validity check on + the subject string. first introduced in ngx_lua v0.8.1. + x extended mode (similar to Perl's /x modifier) These options can be combined: diff --git a/README.markdown b/README.markdown index b7d8d691e9..0e3ceedbdf 100644 --- a/README.markdown +++ b/README.markdown @@ -3422,6 +3422,9 @@ Specify `options` to control how the match operation will be performed. The foll u UTF-8 mode. this requires PCRE to be built with the --enable-utf8 option or else a Lua exception will be thrown. + U similar to "u" but disables PCRE's UTF-8 validity check on + the subject string. first introduced in ngx_lua v0.8.1. + x extended mode (similar to Perl's /x modifier) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 187a6ec089..5aace38c2a 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3304,6 +3304,9 @@ Specify options to control how the match operation will be performe u UTF-8 mode. this requires PCRE to be built with the --enable-utf8 option or else a Lua exception will be thrown. + U similar to "u" but disables PCRE's UTF-8 validity check on + the subject string. first introduced in ngx_lua v0.8.1. + x extended mode (similar to Perl's /x modifier) From d1eca0c72ebcac9694036c9a9229f585d1019d38 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 17:19:12 -0700 Subject: [PATCH 0086/1981] fixed one test case's title. --- t/113-req-header-cookie.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t index 526586073d..2d11f7491a 100644 --- a/t/113-req-header-cookie.t +++ b/t/113-req-header-cookie.t @@ -213,7 +213,7 @@ Cookie: boo=123; foo=78 -=== TEST 6: set one custom cookie (without existing cookies) +=== TEST 6: set multiple custom cookies (without existing cookies) --- config location /t { rewrite_by_lua ' From 30cbc330743c688979a70bbafc1e2367b88d6a4d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 17:23:03 -0700 Subject: [PATCH 0087/1981] fixed several places in the header API where we should return NGX_ERROR instead of NGX_HTTP_INTERNAL_SERVER_ERROR. --- src/ngx_http_lua_headers_in.c | 4 ++-- src/ngx_http_lua_headers_out.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 8391de00da..9d7006cde7 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -198,7 +198,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } dd("created new header for %.*s", (int) hv->key.len, hv->key.data); @@ -215,7 +215,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 2a43c66984..0d34337769 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -192,7 +192,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } if (value->len == 0) { @@ -207,7 +207,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); From f41226883a73cbdd1ba9fe74a8d5e6d1fbe3bc84 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 17:33:31 -0700 Subject: [PATCH 0088/1981] refactor: removed the unused parameter, "no_create", from the ngx_http_set_header_helper function. --- src/ngx_http_lua_headers_in.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 9d7006cde7..f3d8341c8b 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -20,7 +20,7 @@ static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value, - ngx_table_elt_t **output_header, unsigned no_create); + ngx_table_elt_t **output_header); static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r, @@ -125,14 +125,13 @@ static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { - return ngx_http_set_header_helper(r, hv, value, NULL, 0); + return ngx_http_set_header_helper(r, hv, value, NULL); } static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, - ngx_str_t *value, ngx_table_elt_t **output_header, - unsigned no_create) + ngx_str_t *value, ngx_table_elt_t **output_header) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -255,7 +254,7 @@ ngx_http_set_builtin_header(ngx_http_request_t *r, if (old == NULL || *old == NULL) { dd("set normal header"); - return ngx_http_set_header_helper(r, hv, value, old, 0); + return ngx_http_set_header_helper(r, hv, value, old); } h = *old; @@ -264,7 +263,7 @@ ngx_http_set_builtin_header(ngx_http_request_t *r, h->hash = 0; h->value = *value; - return ngx_http_set_header_helper(r, hv, value, old, 0); + return ngx_http_set_header_helper(r, hv, value, old); } h->hash = hv->hash; @@ -425,7 +424,7 @@ ngx_http_set_cookie_header(ngx_http_request_t *r, dd("clear headers in cookies: %d", (int) r->headers_in.cookies.nelts); } - if (ngx_http_set_header_helper(r, hv, value, &h, 0) == NGX_ERROR) { + if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { return NGX_ERROR; } From 3052bcd8a3b75c1ecfe6a12ebd6976ef561dd7dd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 17:57:48 -0700 Subject: [PATCH 0089/1981] updated .gitignore a bit. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ade14fd480..ec113d06ac 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,4 @@ tsubreq tthread addr2line hup +theaders From 790a74e04369d789ed92b11508314e23d1f9a1ef Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 24 Apr 2013 19:07:42 -0700 Subject: [PATCH 0090/1981] bugfix: when lua_http10_buffering is on, for HTTP 1.0 requests, ngx.exit(N) would always trigger the nginx's own error pages when N >= 300. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_util.c | 14 ++++++++++++++ t/005-exit.t | 22 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index abe9e32bda..dc2abb970c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2160,6 +2160,20 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_lua_request_cleanup(r); + if (ctx->buffering && r->headers_out.status) { + rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + if (ctx->exit_code >= NGX_HTTP_OK) { + return NGX_HTTP_OK; + } + + return ctx->exit_code; + } + if ((ctx->exit_code == NGX_OK && ctx->entered_content_phase) || (ctx->exit_code >= NGX_HTTP_OK diff --git a/t/005-exit.t b/t/005-exit.t index fdd82730c4..ee8f7c0a13 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -11,7 +11,7 @@ repeat_each(2); #log_level('warn'); #worker_connections(1024); -plan tests => repeat_each() * (blocks() * 3 + 3); +plan tests => repeat_each() * (blocks() * 3 + 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -543,3 +543,23 @@ Hello World [error] [alert] + + +=== TEST 16: throw 403 after sending out headers with 403 (HTTP 1.0 buffering) +--- config + location /t { + rewrite_by_lua ' + ngx.status = 403 + ngx.say("Hello World") + ngx.exit(403) + '; + } +--- request +GET /t HTTP/1.0 +--- response_body +Hello World +--- error_code: 403 +--- no_error_log +[error] +[alert] + From 65ff8d86daeb42d97e9403b0083e5a83179e6774 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 25 Apr 2013 22:56:53 -0700 Subject: [PATCH 0091/1981] fixed a test case that may behave slighly differently on slow machines. --- t/106-timer.t | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/t/106-timer.t b/t/106-timer.t index 3fcdfda07e..8285305100 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -1375,8 +1375,8 @@ F(ngx_http_lua_sleep_cleanup) { } _EOC_ ---- stap_out -create 2 in 1 +--- stap_out_like chop +(?:create 2 in 1 terminate 1: ok delete thread 1 free request @@ -1389,7 +1389,20 @@ terminate 3: ok lua sleep cleanup delete timer 1000 delete thread 3 -delete thread 2 +delete thread 2|create 2 in 1 +terminate 1: ok +delete thread 1 +create 3 in 2 +spawn user thread 3 in 2 +add timer 100 +add timer 1000 +free request +expire timer 100 +terminate 3: ok +lua sleep cleanup +delete timer 1000 +delete thread 3 +delete thread 2)$ --- response_body registered timer From 04c81b1f84c12c4bed9a9a31b86d03b29525eea6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 25 Apr 2013 23:06:59 -0700 Subject: [PATCH 0092/1981] minor coding style fixes. --- src/ngx_http_lua_socket_tcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index e24f9fe061..34c6fad1b6 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2081,7 +2081,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2098,7 +2098,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } @@ -2129,7 +2129,7 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); + NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } From c558c4347b289ac96e8ad09501629f79251b3911 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 26 Apr 2013 12:27:52 -0700 Subject: [PATCH 0093/1981] bumped version to 0.8.1. --- doc/HttpLuaModule.wiki | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5aace38c2a..9f5caff91e 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.0] released on 23 April 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.1] released on 26 April 2013. = Synopsis = @@ -306,7 +306,7 @@ When Nginx receives the HUP signal and starts reloading the config Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: - init_by_lua 'require "cjson"'; + init_by_lua 'cjson = require "cjson"'; server { location = /api { @@ -5026,7 +5026,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.7) +* 1.2.x (last tested: 1.2.8) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -5050,9 +5050,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' - tar -xzvf nginx-1.2.7.tar.gz - cd nginx-1.2.7/ + wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' + tar -xzvf nginx-1.2.8.tar.gz + cd nginx-1.2.8/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From e7dff1b3016435fabc33ebbdaa0b18adee1ee4d8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 26 Apr 2013 12:41:21 -0700 Subject: [PATCH 0094/1981] updated the docs in plain text and markdown format to reflect recent changes. --- README | 14 +++++++------- README.markdown | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README b/README index 5b3b4d86f3..ab2f2b6756 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.0 - () released on 23 + This document describes ngx_lua v0.8.1 + () released on 26 April 2013. Synopsis @@ -346,7 +346,7 @@ Directives modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: - init_by_lua 'require "cjson"'; + init_by_lua 'cjson = require "cjson"'; server { location = /api { @@ -5847,7 +5847,7 @@ Nginx Compatibility * 1.3.x (last tested: 1.3.11) - * 1.2.x (last tested: 1.2.7) + * 1.2.x (last tested: 1.2.8) * 1.1.x (last tested: 1.1.5) @@ -5888,9 +5888,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' - tar -xzvf nginx-1.2.7.tar.gz - cd nginx-1.2.7/ + wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' + tar -xzvf nginx-1.2.8.tar.gz + cd nginx-1.2.8/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/README.markdown b/README.markdown index 0e3ceedbdf..8492a29f45 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.0](https://github.com/chaoslawful/lua-nginx-module/tags) released on 23 April 2013. +This document describes ngx_lua [v0.8.1](https://github.com/chaoslawful/lua-nginx-module/tags) released on 26 April 2013. Synopsis ======== @@ -322,7 +322,7 @@ When Nginx receives the `HUP` signal and starts reloading the config file, the L Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: - init_by_lua 'require "cjson"'; + init_by_lua 'cjson = require "cjson"'; server { location = /api { @@ -5199,7 +5199,7 @@ Nginx Compatibility The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.7) +* 1.2.x (last tested: 1.2.8) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -5225,9 +5225,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.7.tar.gz' - tar -xzvf nginx-1.2.7.tar.gz - cd nginx-1.2.7/ + wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' + tar -xzvf nginx-1.2.8.tar.gz + cd nginx-1.2.8/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From 34411875fbea22f4f1ae2a64d3b39f3a3123b3a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 27 Apr 2013 12:48:16 -0700 Subject: [PATCH 0095/1981] added error log checks to the bytecode tests. --- t/081-bytecode.t | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/t/081-bytecode.t b/t/081-bytecode.t index f67e117c20..5cba575546 100644 --- a/t/081-bytecode.t +++ b/t/081-bytecode.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 3); #no_diff(); #no_long_string(); @@ -45,6 +45,8 @@ __DATA__ \x1b\x4c\x4a\x01\x02\x29\x02\x00\x02\x00\x03\x00\x05\x34\x00\x00\x00\x37\x00\x01\x00\x25\x01\x02\x00\x3e\x00\x02\x01\x47\x00\x01\x00\x0a\x68\x65\x6c\x6c\x6f\x08\x73\x61\x79\x08\x6e\x67\x78\x00" --- response_body hello +--- no_error_log +[error] @@ -154,6 +156,8 @@ bad byte-code header in \x1b\x4c\x4a\x01\x03\x29\x02\x00\x02\x00\x03\x00\x05\x00\x00\x00\x34\x00\x01\x00\x37\x00\x02\x01\x25\x01\x02\x00\x3e\x00\x01\x00\x47\x0a\x68\x65\x6c\x6c\x6f\x08\x73\x61\x79\x08\x6e\x67\x78\x00" --- response_body ok +--- no_error_log +[error] @@ -196,6 +200,8 @@ ok \x1b\x4c\x4a\x01\x02\x29\x02\x00\x02\x00\x03\x00\x05\xff\xff\xff\xff\x37\x00\x01\x00\x25\x01\x02\x00\x3e\x00\x02\x01\x47\x00\x01\x00\x0a\x68\x65\x6c\x6c\x6f\x08\x73\x61\x79\x08\x6e\x67\x78\x00" --- response_body error +--- no_error_log +[error] @@ -226,4 +232,6 @@ error \x1b\x4c\x4a\x01\x00\x09\x40\x74\x65\x73\x74\x2e\x6c\x75\x61\x32\x02\x00\x02\x00\x03\x00\x05\x06\x00\x02\x34\x00\x00\x00\x37\x00\x01\x00\x25\x01\x02\x00\x3e\x00\x02\x01\x47\x00\x01\x00\x0a\x68\x65\x6c\x6c\x6f\x08\x73\x61\x79\x08\x6e\x67\x78\x01\x01\x01\x01\x01\x00\x00" --- response_body hello +--- no_error_log +[error] From cea321f7f9e2614c9e0932e367d15502507fa7e9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 16:46:12 -0700 Subject: [PATCH 0096/1981] added pure C API for ngx.md5, ngx.md5_bin, ngx.sha1_bin, which is expected to be used with LuaJIT FFI (or lua-resty-core in particular). such API can be excluded by specifying the C macro NGX_HTTP_LUA_NO_FFI_API. --- src/ngx_http_lua_string.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index c95489d46c..29758a1fda 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -667,4 +667,43 @@ ngx_http_lua_ngx_hmac_sha1(lua_State *L) } #endif + +#ifndef NGX_HTTP_LUA_NO_FFI_API +void +ngx_http_lua_ffi_md5_bin(const u_char *src, size_t len, u_char *dst) +{ + ngx_md5_t md5; + + ngx_md5_init(&md5); + ngx_md5_update(&md5, src, len); + ngx_md5_final(dst, &md5); +} + + +void +ngx_http_lua_ffi_md5(const u_char *src, size_t len, u_char *dst) +{ + ngx_md5_t md5; + u_char md5_buf[MD5_DIGEST_LENGTH]; + + ngx_md5_init(&md5); + ngx_md5_update(&md5, src, len); + ngx_md5_final(md5_buf, &md5); + + ngx_hex_dump(dst, md5_buf, sizeof(md5_buf)); +} + + +void +ngx_http_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst) +{ + ngx_sha1_t sha; + + ngx_sha1_init(&sha); + ngx_sha1_update(&sha, src, len); + ngx_sha1_final(dst, &sha); +} + +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 6ef7cef0dc444f782499e94b5fcecc61b82ac12b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 21:10:31 -0700 Subject: [PATCH 0097/1981] feature: allow injecting new APIs into the "ngx" table. --- src/ngx_http_lua_misc.c | 15 ++++++++++----- t/015-status.t | 8 +++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index a29d74bfd8..fecc4b242b 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -111,16 +111,16 @@ ngx_http_lua_ngx_set(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx->headers_sent) { @@ -141,10 +141,15 @@ ngx_http_lua_ngx_set(lua_State *L) if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + return ngx_http_lua_ngx_set_ctx(L); } - return luaL_error(L, "attempt to write to ngx. with the key \"%s\"", p); + lua_rawset(L, -3); + return 0; } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/015-status.t b/t/015-status.t index 45624e8678..358b4c54a8 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -10,7 +10,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 3); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -150,8 +150,10 @@ GET /201 } --- request GET /201 ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body +created +--- no_error_log +[error] From c355f0b5bc2abde34f140edf596769b4d92ff0e8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 21:11:20 -0700 Subject: [PATCH 0098/1981] bugfix: failed to compile when SHA1 support is missing. this regression had appeared in cea321f7f9e2614c9e0932e367d15502507fa7e9. --- src/ngx_http_lua_string.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 29758a1fda..fc83187cd8 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -694,14 +694,20 @@ ngx_http_lua_ffi_md5(const u_char *src, size_t len, u_char *dst) } -void +int ngx_http_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst) { +#if NGX_HAVE_SHA1 ngx_sha1_t sha; ngx_sha1_init(&sha); ngx_sha1_update(&sha, src, len); ngx_sha1_final(dst, &sha); + + return 1; +#else + return 0; +#endif } #endif From 0ab77f96403b5628dbfdb12932acc0e41cb0235f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 21:38:45 -0700 Subject: [PATCH 0099/1981] feature: added pure C API for ngx.encode_base64 and ngx.decode_base64, which is expected to be used by lua-resty-core and etc. --- src/ngx_http_lua_string.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index fc83187cd8..6bde99cfcc 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -710,6 +710,42 @@ ngx_http_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst) #endif } + +size_t +ngx_http_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst) +{ + ngx_str_t in, out; + + in.data = (u_char *) src; + in.len = slen; + + out.data = dst; + + ngx_encode_base64(&out, &in); + + return out.len; +} + + +int +ngx_http_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst, + size_t *dlen) +{ + ngx_int_t rc; + ngx_str_t in, out; + + in.data = (u_char *) src; + in.len = slen; + + out.data = dst; + + rc = ngx_decode_base64(&out, &in); + + *dlen = out.len; + + return rc == NGX_OK; +} + #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 5cb2b4946efe98aaa704c9246b776915d894d7fc Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 22:54:08 -0700 Subject: [PATCH 0100/1981] feature: added pure C API for ngx.escape_uri and ngx.unescape_uri, which is expected to be used by lua-resty-core and etc. --- src/ngx_http_lua_string.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 6bde99cfcc..72278a0146 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -746,6 +746,32 @@ ngx_http_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst, return rc == NGX_OK; } + +size_t +ngx_http_lua_ffi_unescape_uri(const u_char *src, size_t len, u_char *dst) +{ + u_char *p = dst; + + ngx_http_lua_unescape_uri(&p, (u_char **) &src, len, + NGX_UNESCAPE_URI_COMPONENT); + return p - dst; +} + + +size_t +ngx_http_lua_ffi_uri_escaped_length(const u_char *src, size_t len) +{ + return len + 2 * ngx_http_lua_escape_uri(NULL, (u_char *) src, len, + NGX_ESCAPE_URI); +} + + +void +ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) +{ + ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_UNESCAPE_URI); +} + #endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From c04c51a2324bff2f4d8d761a889722055b7546a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 3 May 2013 15:49:14 -0700 Subject: [PATCH 0101/1981] bugfix: ngx.req.set_body_file() always enabled Direct I/O which caused the alert message "fcntl(O_DIRECT) ... Invalid argument" in error logs on file systems lacking the Direct I/O support. buffer corruption might happen in ngx.req.set_body_file() when nginx upstream modules are used later because ngx.req.set_body_file() incorrectly set r->request_body->buf to the in-file buffer which could get reused by ngx_http_upstream for its own purposes. thanks Matthieu Tourne for reporting this issue. --- src/ngx_http_lua_req_body.c | 9 ++-- t/044-req-body.t | 88 ++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 2a24de685d..4a61fb72d1 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -904,6 +904,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) ngx_memzero(b, sizeof(ngx_buf_t)); b->tag = tag; + rb->buf = NULL; } else { @@ -923,7 +924,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) b->tag = tag; rb->bufs->buf = b; - rb->buf = b; + rb->buf = NULL; } b->last_in_chain = 1; @@ -963,6 +964,8 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log) != NGX_OK) { @@ -974,9 +977,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) tf->file.fd = of.fd; tf->file.name = name; tf->file.log = r->connection->log; - - /* FIXME we should not always set directio here */ - tf->file.directio = 1; + tf->file.directio = 0; if (of.size == 0) { if (clean) { diff --git a/t/044-req-body.t b/t/044-req-body.t index 1e08855f98..aae674e67b 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -4,11 +4,11 @@ use Test::Nginx::Socket; #worker_connections(1014); #master_process_enabled(1); -#log_level('warn'); +log_level('warn'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 38); +plan tests => repeat_each() * (blocks() * 4 + 35); #no_diff(); no_long_string(); @@ -57,6 +57,7 @@ hello, world" --- error_code_like: ^(?:500)?$ --- no_error_log [error] +[alert] @@ -81,6 +82,7 @@ hello, world sub: foo --- no_error_log [error] +[alert] @@ -105,6 +107,7 @@ hello, world sub: foo --- no_error_log [error] +[alert] @@ -133,6 +136,7 @@ hiya, world"] "body: hiya, world\n"] --- no_error_log [error] +[alert] @@ -162,6 +166,7 @@ qr/400 Bad Request/] [200, ''] --- no_error_log [error] +[alert] @@ -180,6 +185,7 @@ hello, world hello, world --- no_error_log [error] +[alert] @@ -199,6 +205,7 @@ hello, world nil --- no_error_log [error] +[alert] @@ -217,6 +224,7 @@ hello, world --- response_body_like: client_body_temp/ --- no_error_log [error] +[alert] @@ -235,6 +243,7 @@ hello, world nil --- no_error_log [error] +[alert] @@ -258,6 +267,7 @@ hiya, dear hiya, dear --- no_error_log [error] +[alert] @@ -281,6 +291,7 @@ hello, baby hello, baby --- no_error_log [error] +[alert] @@ -347,6 +358,7 @@ X-Old: \S+/client_body_temp/\d+\r Will you change this world? --- no_error_log [error] +[alert] @@ -385,6 +397,7 @@ X-Old: \S+/client_body_temp/\d+\r Will you change this world? --- no_error_log [error] +[alert] @@ -423,6 +436,7 @@ a.txt exists: no b.txt exists: yes --- no_error_log [error] +[alert] @@ -457,6 +471,8 @@ Will you change this world? qr/500 Internal Server Error/] --- error_code eval [200, 500] +--- no_error_log +[alert] @@ -493,6 +509,7 @@ Will you change this world? [200, 200] --- no_error_log [error] +[alert] @@ -583,6 +600,7 @@ hello, world hiya, dear dear friend! --- no_error_log [error] +[alert] @@ -637,6 +655,7 @@ hello, world"] ["nil","nil"] --- no_error_log [error] +[alert] @@ -664,6 +683,7 @@ hello, world"] ["body: [nil]\n","body: [nil]\n"] --- no_error_log [error] +[alert] @@ -693,6 +713,7 @@ hello, world"] ["body: [nil]\n","body: [nil]\n"] --- no_error_log [error] +[alert] @@ -752,6 +773,7 @@ hello, world howdy, my dear little sister! --- no_error_log [error] +[alert] @@ -779,6 +801,7 @@ hello, world howdy, my dear little sister! --- no_error_log [error] +[alert] @@ -802,6 +825,7 @@ hello, world --- response_body chomp --- no_error_log [error] +[alert] @@ -830,6 +854,7 @@ world srcache_store: request body len: 55 --- no_error_log [error] +[alert] @@ -865,6 +890,7 @@ content length: 4 body: hell --- no_error_log [error] +[alert] @@ -923,6 +949,7 @@ body: nil body file: hello --- no_error_log [error] +[alert] --- error_log a client request body is buffered to a temporary file @@ -951,6 +978,8 @@ a client request body is buffered to a temporary file --- error_code: 500 --- error_log lua entry thread aborted: runtime error: [string "content_by_lua"]:2: request body not read yet +--- no_error_log +[alert] @@ -979,6 +1008,7 @@ content length: 4 body: hell --- no_error_log [error] +[alert] --- no_error_log a client request body is buffered to a temporary file @@ -1024,6 +1054,7 @@ probe syscall.unlink { hello --- no_error_log [error] +[alert] --- error_log a client request body is buffered to a temporary file @@ -1054,6 +1085,7 @@ i do like the sky hell --- no_error_log [error] +[alert] a client request body is buffered to a temporary file @@ -1150,6 +1182,7 @@ body: nil body file: hello --- no_error_log [error] +[alert] --- error_log a client request body is buffered to a temporary file @@ -1199,6 +1232,7 @@ content length: 22 body: hello, my dear friend! --- no_error_log [error] +[alert] --- no_error_log a client request body is buffered to a temporary file @@ -1253,6 +1287,7 @@ body: blah blah blah "] --- no_error_log [error] +[alert] --- no_error_log a client request body is buffered to a temporary file @@ -1308,6 +1343,7 @@ body: blah blah blah "] --- no_error_log [error] +[alert] --- no_error_log a client request body is buffered to a temporary file @@ -1337,6 +1373,7 @@ hello, my dear friend! failed to get req socket: request body already exists --- no_error_log [error] +[alert] --- no_error_log a client request body is buffered to a temporary file @@ -1396,3 +1433,50 @@ hello, world [alert] --- skip_nginx: 4: <1.3.9 + + +=== TEST 44: zero size request body and reset it to a new file +--- config + location = /test { + client_body_in_file_only on; + set $old ''; + set $new ''; + rewrite_by_lua ' + ngx.req.read_body() + ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt") + ngx.var.new = ngx.req.get_body_file() + '; + #echo_request_body; + proxy_pass http://127.0.0.1:$server_port/echo; + #proxy_pass http://127.0.0.1:7890/echo; + add_header X-Old $old; + add_header X-New $new; + } + location /echo { + echo_read_request_body; + echo_request_body; + } +--- request +POST /test +--- user_files +>>> a.txt +Will you change this world? + +--- stap +probe syscall.fcntl { + O_DIRECT = 0x4000 + if (pid() == target() && ($arg & O_DIRECT)) { + println("fcntl(O_DIRECT)") + } +} +--- stap_out_unlike +fcntl\(O_DIRECT\) + +--- raw_response_headers_like +.*?X-New: \S+/html/a\.txt\r +--- response_body +Will you change this world? +--- no_error_log +[error] +[alert] + From 1cc76f59782cfc11f511a8ce2019b28e9274b359 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Apr 2013 21:10:31 -0700 Subject: [PATCH 0102/1981] feature: allow injecting new APIs into the "ngx" table. --- src/ngx_http_lua_misc.c | 15 ++++++++++----- t/015-status.t | 8 +++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index a29d74bfd8..fecc4b242b 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -111,16 +111,16 @@ ngx_http_lua_ngx_set(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx->headers_sent) { @@ -141,10 +141,15 @@ ngx_http_lua_ngx_set(lua_State *L) if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + return ngx_http_lua_ngx_set_ctx(L); } - return luaL_error(L, "attempt to write to ngx. with the key \"%s\"", p); + lua_rawset(L, -3); + return 0; } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/015-status.t b/t/015-status.t index 45624e8678..358b4c54a8 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -10,7 +10,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 3); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -150,8 +150,10 @@ GET /201 } --- request GET /201 ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body +created +--- no_error_log +[error] From f442858bb9a3916767e822abb6fd297345fc445c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 3 May 2013 16:18:16 -0700 Subject: [PATCH 0103/1981] minor coding style fixes and micro optimizations in ngx.md5, ngx.encode_base64, and ngx.decode_base64. --- src/ngx_http_lua_string.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index c95489d46c..9b5702b96b 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -354,9 +354,9 @@ ngx_http_lua_ngx_md5(lua_State *L) return luaL_error(L, "expecting one argument"); } - if (strcmp(luaL_typename(L, 1), (char *) "nil") == 0) { - src = (u_char *) ""; - slen = 0; + if (lua_isnil(L, 1)) { + src = (u_char *) ""; + slen = 0; } else { src = (u_char *) luaL_checklstring(L, 1, &slen); @@ -461,9 +461,9 @@ ngx_http_lua_ngx_decode_base64(lua_State *L) return luaL_error(L, "expecting one argument"); } - if (strcmp(luaL_typename(L, 1), (char *) "nil") == 0) { - src.data = (u_char *) ""; - src.len = 0; + if (lua_isnil(L, 1)) { + src.data = (u_char *) ""; + src.len = 0; } else { src.data = (u_char *) luaL_checklstring(L, 1, &src.len); @@ -508,9 +508,9 @@ ngx_http_lua_ngx_encode_base64(lua_State *L) return luaL_error(L, "expecting one argument"); } - if (strcmp(luaL_typename(L, 1), (char *) "nil") == 0) { - src.data = (u_char *) ""; - src.len = 0; + if (lua_isnil(L, 1)) { + src.data = (u_char *) ""; + src.len = 0; } else { src.data = (u_char *) luaL_checklstring(L, 1, &src.len); From b7b728926a28fe46e2fbdebe95653fb2d0d4a0cd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 3 May 2013 16:25:50 -0700 Subject: [PATCH 0104/1981] bugfix: temporary memory leaks might happen when using ngx.escape_uri, ngx.unescape_uri, ngx.quote_sql_str, ngx.decode_base64, and ngx.encode_base64 in tight Lua loops because we allocated memory in nginx's request memory pool for these methods. --- src/ngx_http_lua_string.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 9b5702b96b..39d3a7935a 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -136,10 +136,7 @@ ngx_http_lua_ngx_escape_uri(lua_State *L) dlen = escape + len; - dst = ngx_palloc(r->pool, dlen); - if (dst == NULL) { - return luaL_error(L, "memory allocation error"); - } + dst = lua_newuserdata(L, dlen); if (escape == 0) { ngx_memcpy(dst, src, len); @@ -180,10 +177,7 @@ ngx_http_lua_ngx_unescape_uri(lua_State *L) /* the unescaped string can only be smaller */ dlen = len; - p = ngx_palloc(r->pool, dlen); - if (p == NULL) { - return luaL_error(L, "memory allocation error"); - } + p = lua_newuserdata(L, dlen); dst = p; @@ -229,10 +223,7 @@ ngx_http_lua_ngx_quote_sql_str(lua_State *L) dlen = sizeof("''") - 1 + len + escape; - p = ngx_palloc(r->pool, dlen); - if (p == NULL) { - return luaL_error(L, "out of memory"); - } + p = lua_newuserdata(L, dlen); dst = p; @@ -471,10 +462,7 @@ ngx_http_lua_ngx_decode_base64(lua_State *L) p.len = ngx_base64_decoded_length(src.len); - p.data = ngx_palloc(r->pool, p.len); - if (p.data == NULL) { - return NGX_ERROR; - } + p.data = lua_newuserdata(L, p.len); if (ngx_decode_base64(&p, &src) == NGX_OK) { lua_pushlstring(L, (char *) p.data, p.len); @@ -518,10 +506,7 @@ ngx_http_lua_ngx_encode_base64(lua_State *L) p.len = ngx_base64_encoded_length(src.len); - p.data = ngx_palloc(r->pool, p.len); - if (p.data == NULL) { - return NGX_ERROR; - } + p.data = lua_newuserdata(L, p.len); ngx_encode_base64(&p, &src); From 601ddff378b71a7d8903925bef5fd8f9496a4677 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 3 May 2013 16:30:35 -0700 Subject: [PATCH 0105/1981] optimize: ngx.escape_uri now runs faster when the input string contains no special chars to be escaped. --- src/ngx_http_lua_string.c | 15 ++++----------- t/006-escape.t | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 39d3a7935a..9775457307 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -128,25 +128,18 @@ ngx_http_lua_ngx_escape_uri(lua_State *L) src = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { - lua_pushlstring(L, NULL, 0); return 1; } escape = 2 * ngx_http_lua_escape_uri(NULL, src, len, NGX_ESCAPE_URI); - dlen = escape + len; - - dst = lua_newuserdata(L, dlen); - - if (escape == 0) { - ngx_memcpy(dst, src, len); - - } else { + if (escape) { + dlen = escape + len; + dst = lua_newuserdata(L, dlen); ngx_http_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI); + lua_pushlstring(L, (char *) dst, dlen); } - lua_pushlstring(L, (char *) dst, dlen); - return 1; } diff --git a/t/006-escape.t b/t/006-escape.t index 18a826cf79..636e0fd25f 100644 --- a/t/006-escape.t +++ b/t/006-escape.t @@ -105,3 +105,28 @@ baz: %20 --- response_body hello + + +=== TEST 8: escape a string that cannot be escaped +--- config + location /escape { + set_by_lua $res "return ngx.escape_uri('abc')"; + echo $res; + } +--- request +GET /escape +--- response_body +abc + + + +=== TEST 9: escape an empty string that cannot be escaped +--- config + location /escape { + set_by_lua $res "return ngx.escape_uri('')"; + echo $res; + } +--- request +GET /escape +--- response_body eval: "\n" + From b4c2ad1f8e37156a67f5373277a8335d3315221e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 12:34:30 -0700 Subject: [PATCH 0106/1981] feature: added ngx.HTTP_MKCOL, ngx.HTTP_COPY, ngx.HTTP_MOVE, and other WebDAV request method constants; also added corresponding support to ngx.req.set_method and ngx.location.capture. thanks Adallom Roy for the patch. --- src/ngx_http_lua_consts.c | 27 +++++++++++++++++++ src/ngx_http_lua_req_method.c | 36 +++++++++++++++++++++++++ src/ngx_http_lua_subrequest.c | 51 +++++++++++++++++++++++++++++++++++ src/ngx_http_lua_subrequest.h | 9 +++++++ src/ngx_http_lua_util.c | 2 +- t/020-subrequest.t | 45 +++++++++++++++++++++++++++++++ t/062-count.t | 8 +++--- t/088-req-method.t | 41 +++++++++++++++++++++++++++- 8 files changed, 213 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_consts.c b/src/ngx_http_lua_consts.c index 3ff52bb43a..a57859496a 100644 --- a/src/ngx_http_lua_consts.c +++ b/src/ngx_http_lua_consts.c @@ -60,6 +60,33 @@ ngx_http_lua_inject_http_consts(lua_State *L) lua_pushinteger(L, NGX_HTTP_OPTIONS); lua_setfield(L, -2, "HTTP_OPTIONS"); + + lua_pushinteger(L, NGX_HTTP_MKCOL); + lua_setfield(L, -2, "HTTP_MKCOL"); + + lua_pushinteger(L, NGX_HTTP_COPY); + lua_setfield(L, -2, "HTTP_COPY"); + + lua_pushinteger(L, NGX_HTTP_MOVE); + lua_setfield(L, -2, "HTTP_MOVE"); + + lua_pushinteger(L, NGX_HTTP_PROPFIND); + lua_setfield(L, -2, "HTTP_PROPFIND"); + + lua_pushinteger(L, NGX_HTTP_PROPPATCH); + lua_setfield(L, -2, "HTTP_PROPPATCH"); + + lua_pushinteger(L, NGX_HTTP_LOCK); + lua_setfield(L, -2, "HTTP_LOCK"); + + lua_pushinteger(L, NGX_HTTP_UNLOCK); + lua_setfield(L, -2, "HTTP_UNLOCK"); + + lua_pushinteger(L, NGX_HTTP_PATCH); + lua_setfield(L, -2, "HTTP_PATCH"); + + lua_pushinteger(L, NGX_HTTP_TRACE); + lua_setfield(L, -2, "HTTP_TRACE"); /* }}} */ lua_pushinteger(L, NGX_HTTP_OK); diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index b2d0e3c27a..e221913f45 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -109,6 +109,42 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) r->method_name = ngx_http_lua_options_method; break; + case NGX_HTTP_MKCOL: + r->method_name = ngx_http_lua_mkcol_method; + break; + + case NGX_HTTP_COPY: + r->method_name = ngx_http_lua_copy_method; + break; + + case NGX_HTTP_MOVE: + r->method_name = ngx_http_lua_move_method; + break; + + case NGX_HTTP_PROPFIND: + r->method_name = ngx_http_lua_propfind_method; + break; + + case NGX_HTTP_PROPPATCH: + r->method_name = ngx_http_lua_proppatch_method; + break; + + case NGX_HTTP_LOCK: + r->method_name = ngx_http_lua_lock_method; + break; + + case NGX_HTTP_UNLOCK: + r->method_name = ngx_http_lua_unlock_method; + break; + + case NGX_HTTP_PATCH: + r->method_name = ngx_http_lua_patch_method; + break; + + case NGX_HTTP_TRACE: + r->method_name = ngx_http_lua_trace_method; + break; + default: return luaL_error(L, "unsupported HTTP method: %d", method); diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index fd1074277b..7b63d0ad05 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -34,6 +34,21 @@ ngx_str_t ngx_http_lua_delete_method = ngx_http_lua_method_name("DELETE"); ngx_str_t ngx_http_lua_options_method = ngx_http_lua_method_name("OPTIONS"); +ngx_str_t ngx_http_lua_copy_method = ngx_http_lua_method_name("COPY"); +ngx_str_t ngx_http_lua_move_method = ngx_http_lua_method_name("MOVE"); +ngx_str_t ngx_http_lua_lock_method = ngx_http_lua_method_name("LOCK"); +ngx_str_t ngx_http_lua_mkcol_method = + ngx_http_lua_method_name("MKCOL"); +ngx_str_t ngx_http_lua_propfind_method = + ngx_http_lua_method_name("PROPFIND"); +ngx_str_t ngx_http_lua_proppatch_method = + ngx_http_lua_method_name("PROPPATCH"); +ngx_str_t ngx_http_lua_unlock_method = + ngx_http_lua_method_name("UNLOCK"); +ngx_str_t ngx_http_lua_patch_method = + ngx_http_lua_method_name("PATCH"); +ngx_str_t ngx_http_lua_trace_method = + ngx_http_lua_method_name("TRACE"); static ngx_str_t ngx_http_lua_content_length_header_key = @@ -660,6 +675,42 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, sr->method_name = ngx_http_lua_options_method; break; + case NGX_HTTP_MKCOL: + sr->method_name = ngx_http_lua_mkcol_method; + break; + + case NGX_HTTP_COPY: + sr->method_name = ngx_http_lua_copy_method; + break; + + case NGX_HTTP_MOVE: + sr->method_name = ngx_http_lua_move_method; + break; + + case NGX_HTTP_PROPFIND: + sr->method_name = ngx_http_lua_propfind_method; + break; + + case NGX_HTTP_PROPPATCH: + sr->method_name = ngx_http_lua_proppatch_method; + break; + + case NGX_HTTP_LOCK: + sr->method_name = ngx_http_lua_lock_method; + break; + + case NGX_HTTP_UNLOCK: + sr->method_name = ngx_http_lua_unlock_method; + break; + + case NGX_HTTP_PATCH: + sr->method_name = ngx_http_lua_patch_method; + break; + + case NGX_HTTP_TRACE: + sr->method_name = ngx_http_lua_trace_method; + break; + default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unsupported HTTP method: %u", (unsigned) method); diff --git a/src/ngx_http_lua_subrequest.h b/src/ngx_http_lua_subrequest.h index 1358d6067b..aad4236d84 100644 --- a/src/ngx_http_lua_subrequest.h +++ b/src/ngx_http_lua_subrequest.h @@ -23,6 +23,15 @@ extern ngx_str_t ngx_http_lua_post_method; extern ngx_str_t ngx_http_lua_head_method; extern ngx_str_t ngx_http_lua_delete_method; extern ngx_str_t ngx_http_lua_options_method; +extern ngx_str_t ngx_http_lua_copy_method; +extern ngx_str_t ngx_http_lua_move_method; +extern ngx_str_t ngx_http_lua_lock_method; +extern ngx_str_t ngx_http_lua_mkcol_method; +extern ngx_str_t ngx_http_lua_propfind_method; +extern ngx_str_t ngx_http_lua_proppatch_method; +extern ngx_str_t ngx_http_lua_unlock_method; +extern ngx_str_t ngx_http_lua_patch_method; +extern ngx_str_t ngx_http_lua_trace_method; typedef struct ngx_http_lua_post_subrequest_data_s { diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index dc2abb970c..dde1bd27cb 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -747,7 +747,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - lua_createtable(L, 0 /* narr */, 86 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 95 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); diff --git a/t/020-subrequest.t b/t/020-subrequest.t index cefc9590e8..17768847c2 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -2259,3 +2259,48 @@ truncated: true --- no_error_log [error] + + +=== 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] + diff --git a/t/062-count.t b/t/062-count.t index bce4e80319..a027c2a17a 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 86 +ngx: 95 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 86 --- request GET /test --- response_body -86 +95 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 86 +n = 95 --- no_error_log [error] @@ -301,7 +301,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 86 +ngx. entry count: 95 diff --git a/t/088-req-method.t b/t/088-req-method.t index 7f45958510..6b54ba20e8 100644 --- a/t/088-req-method.t +++ b/t/088-req-method.t @@ -13,7 +13,7 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3); #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -225,3 +225,42 @@ method: GET --- no_error_log [error] + + +=== TEST 11: set GET to WebDAV methods +--- config + location /t { + 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 + ngx.req.set_method(method) + ngx.say("method: ", ngx.var.echo_request_method) + end + '; + } +--- request + HEAD /t +--- response_body +method: MKCOL +method: COPY +method: MOVE +method: PROPFIND +method: PROPPATCH +method: LOCK +method: UNLOCK +method: PATCH +method: TRACE +--- no_error_log +[error] + From 41e3c2f5b9511025b6aaa3dff8c27e1c5bde7219 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 13:01:29 -0700 Subject: [PATCH 0107/1981] docs: documented the new WebDAV request methods; also fixed a small typo. --- README | 19 ++++++++++++++----- README.markdown | 13 +++++++++++-- doc/HttpLuaModule.wiki | 13 +++++++++++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/README b/README index ab2f2b6756..bcc3535c8f 100644 --- a/README +++ b/README @@ -1546,7 +1546,16 @@ Nginx API for Lua ngx.HTTP_PUT ngx.HTTP_POST ngx.HTTP_DELETE - ngx.HTTP_OPTIONS (first introduced in the v0.5.0rc24 release) + ngx.HTTP_OPTIONS (added in the v0.5.0rc24 release) + ngx.HTTP_MKCOL (added in the v0.8.2 release) + ngx.HTTP_COPY (added in the v0.8.2 release) + ngx.HTTP_MOVE (added in the v0.8.2 release) + ngx.HTTP_PROPFIND (added in the v0.8.2 release) + ngx.HTTP_PROPPATCH (added in the v0.8.2 release) + ngx.HTTP_LOCK (added in the v0.8.2 release) + ngx.HTTP_UNLOCK (added in the v0.8.2 release) + ngx.HTTP_PATCH (added in the v0.8.2 release) + ngx.HTTP_TRACE (added in the v0.8.2 release) These constants are usually used in ngx.location.capture and ngx.location.capture_multi method calls. @@ -5362,10 +5371,10 @@ Nginx API for Lua callbacks, like stream/datagram cosockets (ngx.socket.tcp and ngx.socket.udp), shared memory dictionaries (ngx.shared.DICT), user coroutines (coroutine.*), user "light threads" (ngx.thread.*), ngx.exit, - ngx.now/ngx.time, ngx.md5/ngx.sha1, are all allowed. But the subrequest - API (like ngx.location.capture), the ngx.req.* API, the downstream - output API (like ngx.say, ngx.print, and ngx.flush) are explicitly - disabled in this context. + ngx.now/ngx.time, ngx.md5/ngx.sha1_bin, are all allowed. But the + subrequest API (like ngx.location.capture), the ngx.req.* API, the + downstream output API (like ngx.say, ngx.print, and ngx.flush) are + explicitly disabled in this context. This API was first introduced in the "v0.8.0" release. diff --git a/README.markdown b/README.markdown index 8492a29f45..94bf0e634f 100644 --- a/README.markdown +++ b/README.markdown @@ -1364,7 +1364,16 @@ HTTP method constants ngx.HTTP_PUT ngx.HTTP_POST ngx.HTTP_DELETE - ngx.HTTP_OPTIONS (first introduced in the v0.5.0rc24 release) + ngx.HTTP_OPTIONS (added in the v0.5.0rc24 release) + ngx.HTTP_MKCOL (added in the v0.8.2 release) + ngx.HTTP_COPY (added in the v0.8.2 release) + ngx.HTTP_MOVE (added in the v0.8.2 release) + ngx.HTTP_PROPFIND (added in the v0.8.2 release) + ngx.HTTP_PROPPATCH (added in the v0.8.2 release) + ngx.HTTP_LOCK (added in the v0.8.2 release) + ngx.HTTP_UNLOCK (added in the v0.8.2 release) + ngx.HTTP_PATCH (added in the v0.8.2 release) + ngx.HTTP_TRACE (added in the v0.8.2 release) These constants are usually used in [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) method calls. @@ -4808,7 +4817,7 @@ A lot of the Lua APIs for Nginx are enabled in the context of the timer callbacks, like stream/datagram cosockets ([ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.socket.udp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.udp)), shared memory dictionaries ([ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT)), user coroutines ([coroutine.*](http://wiki.nginx.org/HttpLuaModule#coroutine.create)), user "light threads" ([ngx.thread.*](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn)), [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit), [ngx.now](http://wiki.nginx.org/HttpLuaModule#ngx.now)/[ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time), -[ngx.md5](http://wiki.nginx.org/HttpLuaModule#ngx.md5)/[ngx.sha1](http://wiki.nginx.org/HttpLuaModule#ngx.sha1), are all allowed. But the subrequest API (like +[ngx.md5](http://wiki.nginx.org/HttpLuaModule#ngx.md5)/[ngx.sha1_bin](http://wiki.nginx.org/HttpLuaModule#ngx.sha1_bin), are all allowed. But the subrequest API (like [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture)), the [ngx.req.*](http://wiki.nginx.org/HttpLuaModule#ngx.req.start_time) API, the downstream output API (like [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say), [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print), and [ngx.flush](http://wiki.nginx.org/HttpLuaModule#ngx.flush)) are explicitly disabled in this context. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9f5caff91e..f428a7008f 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1311,7 +1311,16 @@ The ngx.DECLINED constant was first introduced in the v0.5.0r ngx.HTTP_PUT ngx.HTTP_POST ngx.HTTP_DELETE - ngx.HTTP_OPTIONS (first introduced in the v0.5.0rc24 release) + ngx.HTTP_OPTIONS (added in the v0.5.0rc24 release) + ngx.HTTP_MKCOL (added in the v0.8.2 release) + ngx.HTTP_COPY (added in the v0.8.2 release) + ngx.HTTP_MOVE (added in the v0.8.2 release) + ngx.HTTP_PROPFIND (added in the v0.8.2 release) + ngx.HTTP_PROPPATCH (added in the v0.8.2 release) + ngx.HTTP_LOCK (added in the v0.8.2 release) + ngx.HTTP_UNLOCK (added in the v0.8.2 release) + ngx.HTTP_PATCH (added in the v0.8.2 release) + ngx.HTTP_TRACE (added in the v0.8.2 release) These constants are usually used in [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] method calls. @@ -4653,7 +4662,7 @@ A lot of the Lua APIs for Nginx are enabled in the context of the timer callbacks, like stream/datagram cosockets ([[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.socket.udp|ngx.socket.udp]]), shared memory dictionaries ([[#ngx.shared.DICT|ngx.shared.DICT]]), user coroutines ([[#coroutine.create|coroutine.*]]), user "light threads" ([[#ngx.thread.spawn|ngx.thread.*]]), [[#ngx.exit|ngx.exit]], [[#ngx.now|ngx.now]]/[[#ngx.time|ngx.time]], -[[#ngx.md5|ngx.md5]]/[[#ngx.sha1|ngx.sha1]], are all allowed. But the subrequest API (like +[[#ngx.md5|ngx.md5]]/[[#ngx.sha1_bin|ngx.sha1_bin]], are all allowed. But the subrequest API (like [[#ngx.location.capture|ngx.location.capture]]), the [[#ngx.req.start_time|ngx.req.*]] API, the downstream output API (like [[#ngx.say|ngx.say]], [[#ngx.print|ngx.print]], and [[#ngx.flush|ngx.flush]]) are explicitly disabled in this context. From 4806fc2eefa925308650ba514e5530d966f3ba81 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 16:03:03 -0700 Subject: [PATCH 0108/1981] bugfix: fixed the warning "argument 'nret' might be clobbered by 'longjmp' or 'vfork'" when compiling with Ubuntu 13.04's gcc 4.7.3. thanks jacky and Rajeev's reports. --- src/ngx_http_lua_util.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index dde1bd27cb..7a8aad43f1 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -984,10 +984,10 @@ ngx_http_lua_request_cleanup(void *data) */ ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int nret) + ngx_http_lua_ctx_t *ctx, volatile int nrets) { ngx_http_lua_co_ctx_t *next_coctx, *parent_coctx, *orig_coctx; - int rv, nrets, success = 1; + int rv, success = 1; lua_State *next_co; lua_State *old_co; const char *err, *msg, *trace; @@ -1012,15 +1012,12 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->cur_co_ctx->thread_spawn_yielded = 0; nrets = 1; - - } else { - nrets = nret; } for ( ;; ) { dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, - (int) nret); + (int) nrets); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ From 35e6a65f9f7e8b7f093247ce7795c272bb1af85b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 18:07:41 -0700 Subject: [PATCH 0109/1981] change: made the error messages for regex compilation failures less verbose. --- src/ngx_http_lua_regex.c | 18 +++--------------- t/034-match.t | 6 +++--- t/035-gmatch.t | 2 +- t/036-sub.t | 2 +- t/038-match-o.t | 2 +- t/047-match-jit.t | 2 +- t/049-gmatch-jit.t | 2 +- t/050-gmatch-dfa.t | 2 +- t/051-sub-jit.t | 4 ++-- t/052-sub-dfa.t | 4 ++-- t/053-gsub-jit.t | 4 ++-- t/054-gsub-dfa.t | 4 ++-- 12 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 0ae60bc338..60193368e8 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -288,11 +288,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) dd("compile failed"); lua_pushnil(L); - - re_comp.err.data[re_comp.err.len] = '\0'; - msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", - pat.data, re_comp.err.data); - + lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); return 2; } @@ -711,11 +707,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("compile failed"); lua_pushnil(L); - - re_comp.err.data[re_comp.err.len] = '\0'; - msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", - pat.data, re_comp.err.data); - + lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); return 2; } @@ -1397,11 +1389,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) lua_pushnil(L); lua_pushnil(L); - - re_comp.err.data[re_comp.err.len] = '\0'; - msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", - pat.data, re_comp.err.data); - + lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); return 3; } diff --git a/t/034-match.t b/t/034-match.t index c76c520b2f..728bc67ecc 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -241,7 +241,7 @@ hello --- request GET /re --- response_body_like chop -^(?:FAIL: bad argument \#2 to '\?' \(failed to compile regex "HELLO\.\{2\}": pcre_compile\(\) failed: this version of PCRE is not compiled with PCRE_UTF8 support in "HELLO\.\{2\}" at "HELLO\.\{2\}"\)|hello章亦)$ +^(?:FAIL: bad argument \#2 to '\?' \(pcre_compile\(\) failed: this version of PCRE is not compiled with PCRE_UTF8 support in "HELLO\.\{2\}" at "HELLO\.\{2\}"\)|hello章亦)$ @@ -362,7 +362,7 @@ he --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] @@ -649,7 +649,7 @@ regex: (?:>[\w\s]*) --- request GET /re --- response_body -error: failed to compile regex "([0-9]+": pcre_compile() failed: missing ) in "([0-9]+" +error: pcre_compile() failed: missing ) in "([0-9]+" --- no_error_log [error] diff --git a/t/035-gmatch.t b/t/035-gmatch.t index a5c7c82681..3621c9be22 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -699,7 +699,7 @@ not matched! --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/036-sub.t b/t/036-sub.t index 18d2715a95..b2c2c85240 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -476,7 +476,7 @@ a [b c] [b] [c] [] [] d --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/038-match-o.t b/t/038-match-o.t index 494f9f564d..23fada6f84 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -338,7 +338,7 @@ he --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/047-match-jit.t b/t/047-match-jit.t index ff1f59c65a..10333ccbe9 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -122,7 +122,7 @@ pcre JIT compiling result: 1 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t index 401659ce99..4bf131bcfd 100644 --- a/t/049-gmatch-jit.t +++ b/t/049-gmatch-jit.t @@ -208,7 +208,7 @@ pcre JIT compiling result: 1 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index a8a97d5171..ba57380752 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -213,7 +213,7 @@ hello --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/051-sub-jit.t b/t/051-sub-jit.t index c32fd96e43..6e1f6c0f07 100644 --- a/t/051-sub-jit.t +++ b/t/051-sub-jit.t @@ -116,7 +116,7 @@ pcre JIT compiling result: 1 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] @@ -137,7 +137,7 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index 23418634f4..a92bcb6376 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -109,7 +109,7 @@ hello, world: 0 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] @@ -131,7 +131,7 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/053-gsub-jit.t b/t/053-gsub-jit.t index c1b3cd219f..ff90afc376 100644 --- a/t/053-gsub-jit.t +++ b/t/053-gsub-jit.t @@ -116,7 +116,7 @@ pcre JIT compiling result: 1 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] @@ -137,7 +137,7 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index a4527267f8..2ea1d046a9 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -109,7 +109,7 @@ hello, world: 0 --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" @@ -128,7 +128,7 @@ error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc --- request GET /re --- response_body -error: failed to compile regex "(abc": pcre_compile() failed: missing ) in "(abc" +error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] From 5c5a0a87bafe08e8080d0b31ad5afa3f3ce1aebb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 18:25:19 -0700 Subject: [PATCH 0110/1981] change: made the error messages for regex exec failures less verbose. --- src/ngx_http_lua_regex.c | 5 ++--- t/036-sub.t | 2 +- t/037-gsub.t | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 60193368e8..124d674e1c 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1619,9 +1619,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\" " - "using \"%s\"", (int) rc, subj.data, - pat.data); + msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", + (int) rc); goto error; } diff --git a/t/036-sub.t b/t/036-sub.t index b2c2c85240..297fefc124 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -502,7 +502,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- request GET /t --- response_body_like chop -error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" +error: pcre_exec\(\) failed: -10 --- no_error_log [error] diff --git a/t/037-gsub.t b/t/037-gsub.t index 31b97e63ae..4f325b446a 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -425,7 +425,7 @@ n: 1 --- request GET /t --- response_body_like chop -error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" +error: pcre_exec\(\) failed: -10 --- no_error_log [error] From 9b8a7b5e033f0a4e4bdd1f43fcf786e94d8d558f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 18:30:19 -0700 Subject: [PATCH 0111/1981] change: made more error messages for regex exec failures less verbose. --- src/ngx_http_lua_regex.c | 3 +-- t/034-match.t | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 124d674e1c..6f9d70c331 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -474,8 +474,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) } if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\" " - "using \"%s\"", (int) rc, subj.data, pat.data); + msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc); goto error; } diff --git a/t/034-match.t b/t/034-match.t index 728bc67ecc..93c216025a 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -940,7 +940,7 @@ nil --- request GET /t --- response_body_like chop -error: pcre_exec\(\) failed: -10 on "你.*?" using "你好" +^error: pcre_exec\(\) failed: -10$ --- no_error_log [error] From 31a80431ccc8d1d3a76fdcf29ddd5f3e8cb423fe Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 18:54:20 -0700 Subject: [PATCH 0112/1981] fixed some expected error messages in the ngx.re test cases for Lua implementations of the ngx_lua API like lua-resty-core. --- t/034-match.t | 4 ++-- t/038-match-o.t | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/t/034-match.t b/t/034-match.t index 93c216025a..f45eae82c3 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -386,8 +386,8 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: bad argument #3 to '?' (unknown flag "H") +--- response_body_like chop +error: .*?unknown flag "H" diff --git a/t/038-match-o.t b/t/038-match-o.t index 23fada6f84..b8f96a6c86 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -362,8 +362,8 @@ error: pcre_compile() failed: missing ) in "(abc" } --- request GET /re ---- response_body -error: bad argument #3 to '?' (unknown flag "H") +--- response_body_like chop +^error: .*?unknown flag "H" From 170d8f9d7a8356e8c7fd1d374d9bfb796c4364cb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 19:05:04 -0700 Subject: [PATCH 0113/1981] bugfix: ngx_http_lua_ffi_escape_uri did URI unescaping instead of URI escaping. --- src/ngx_http_lua_string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index c029d35b0b..4f9c0f356d 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -747,7 +747,7 @@ ngx_http_lua_ffi_uri_escaped_length(const u_char *src, size_t len) void ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) { - ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_UNESCAPE_URI); + ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI); } #endif From 1f1a31c7bdc2171e184c5e7ac516f12ddcff82c3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 19:13:59 -0700 Subject: [PATCH 0114/1981] feature: added pure C API for ngx.re.match, which is expected to be used by lua-resty-core and etc. --- src/ngx_http_lua_regex.c | 205 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 6f9d70c331..8100b3dc5d 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -44,11 +44,19 @@ typedef struct { - pcre *regex; - pcre_extra *regex_sd; +#ifndef NGX_HTTP_LUA_NO_FFI_API + ngx_pool_t *pool; + u_char *name_table; + int name_count; + int name_entry_size; +#endif + int ncaptures; int *captures; + pcre *regex; + pcre_extra *regex_sd; + ngx_http_lua_complex_value_t *replace; } ngx_http_lua_regex_t; @@ -1990,6 +1998,199 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, } } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +ngx_http_lua_regex_t * +ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, + int flags, int pcre_opts, u_char *errstr, + size_t errstr_size) +{ + int *cap = NULL, ovecsize; + u_char *p; + ngx_int_t rc; + const char *msg; + ngx_pool_t *pool, *old_pool; + pcre_extra *sd = NULL; + ngx_http_lua_regex_t *re; + + ngx_http_lua_regex_compile_t re_comp; + + pool = ngx_create_pool(512, ngx_cycle->log); + if (pool == NULL) { + msg = "no memory"; + goto error; + } + + re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); + if (re == NULL) { + ngx_destroy_pool(pool); + pool = NULL; + msg = "no memory"; + goto error; + } + + re->pool = pool; + + re_comp.options = pcre_opts; + re_comp.pattern.data = (u_char *) pat; + re_comp.pattern.len = pat_len; + re_comp.err.len = errstr_size; + re_comp.err.data = errstr; + re_comp.pool = pool; + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + rc = ngx_http_lua_regex_compile(&re_comp); + ngx_http_lua_pcre_malloc_done(old_pool); + + if (rc != NGX_OK) { + re_comp.err.data[re_comp.err.len] = '\0'; + return NULL; + } + +#if (LUA_HAVE_PCRE_JIT) + + if (flags & NGX_LUA_RE_MODE_JIT) { + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); + ngx_http_lua_pcre_malloc_done(old_pool); + + } else { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + sd = pcre_study(re_comp.regex, 0, &msg); + ngx_http_lua_pcre_malloc_done(old_pool); + } + +#endif /* LUA_HAVE_PCRE_JIT */ + + if (flags & NGX_LUA_RE_MODE_DFA) { + ovecsize = 2; + + } else { + ovecsize = (re_comp.captures + 1) * 3; + } + + dd("allocating cap with size: %d", (int) ovecsize); + + cap = ngx_palloc(pool, ovecsize * sizeof(int)); + if (cap == NULL) { + msg = "no memory"; + goto error; + } + + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT, + &re->name_count) != 0) + { + msg = "cannot acquire named subpattern count"; + goto error; + } + + if (re->name_count > 0) { + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE, + &re->name_entry_size) != 0) + { + msg = "cannot acquire named subpattern entry size"; + goto error; + } + + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE, + &re->name_table) != 0) + { + msg = "cannot acquire named subpattern table"; + goto error; + } + } + + re->regex = re_comp.regex; + re->regex_sd = sd; + re->ncaptures = re_comp.captures; + re->captures = cap; + re->replace = NULL; + + return re; + +error: + p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg); + *p = '\0'; + + if (sd) { + ngx_http_lua_regex_free_study_data(pool, sd); + } + + if (pool) { + ngx_destroy_pool(pool); + } + + return NULL; +} + + +int +ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, + const u_char *s, size_t len, int pos) +{ + int rc, ovecsize, exec_opts, *cap; + ngx_str_t subj; + pcre_extra *sd; + + cap = re->captures; + sd = re->regex_sd; + + if (flags & NGX_LUA_RE_MODE_DFA) { + ovecsize = 2; + + } else { + ovecsize = (re->ncaptures + 1) * 3; + } + + if (flags & NGX_LUA_RE_NO_UTF8_CHECK) { + exec_opts = PCRE_NO_UTF8_CHECK; + + } else { + exec_opts = 0; + } + + subj.data = (u_char *) s; + subj.len = len; + + if (flags & NGX_LUA_RE_MODE_DFA) { + +#if LUA_HAVE_PCRE_DFA + + int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; + rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj, + (int) pos, cap, ovecsize, ws, + sizeof(ws)/sizeof(ws[0]), exec_opts); + +#else /* LUA_HAVE_PCRE_DFA */ + + return PCRE_ERROR_INTERNAL; + +#endif /* LUA_HAVE_PCRE_DFA */ + + } else { + rc = ngx_http_lua_regex_exec(re->regex, sd, &subj, (int) pos, cap, + ovecsize, exec_opts); + } + + return rc; +} + + +void +ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) +{ + dd("destroy regex called"); + + if (re == NULL || re->pool == NULL) { + return; + } + + ngx_destroy_pool(re->pool); +} +#endif /* NGX_HTTP_LUA_NO_FFI_API */ + + #endif /* NGX_PCRE */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 71e16c46d2bbd9e2b76ec64b4cc0e2ac9929ab33 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 19:27:48 -0700 Subject: [PATCH 0115/1981] added custom test scaffold t::TestNginxLua which subclasses Test::Nginx::Socket. it supports the environment TEST_NGINX_INIT_BY_LUA which can be used to add more custom Lua code to the value of the init_by_lua directive in the nginx configuration. --- t/000--init.t | 2 +- t/000-sanity.t | 2 +- t/001-set.t | 2 +- t/002-content.t | 2 +- t/003-errors.t | 2 +- t/004-require.t | 2 +- t/005-exit.t | 2 +- t/006-escape.t | 2 +- t/007-md5.t | 2 +- t/008-today.t | 2 +- t/009-log.t | 2 +- t/010-request_body.t | 2 +- t/011-md5_bin.t | 2 +- t/012-now.t | 2 +- t/013-base64.t | 2 +- t/014-bugs.t | 2 +- t/015-status.t | 2 +- t/016-resp-header.t | 2 +- t/017-exec.t | 2 +- t/018-ndk.t | 2 +- t/019-const.t | 2 +- t/020-subrequest.t | 2 +- t/021-cookie-time.t | 2 +- t/022-redirect.t | 2 +- t/023-rewrite/client-abort.t | 2 +- t/023-rewrite/exec.t | 2 +- t/023-rewrite/exit.t | 2 +- t/023-rewrite/mixed.t | 2 +- t/023-rewrite/multi-capture.t | 2 +- t/023-rewrite/on-abort.t | 2 +- t/023-rewrite/redirect.t | 2 +- t/023-rewrite/req-body.t | 2 +- t/023-rewrite/req-socket.t | 2 +- t/023-rewrite/request_body.t | 2 +- t/023-rewrite/sanity.t | 2 +- t/023-rewrite/sleep.t | 2 +- t/023-rewrite/socket-keepalive.t | 2 +- t/023-rewrite/subrequest.t | 2 +- t/023-rewrite/tcp-socket-timeout.t | 2 +- t/023-rewrite/tcp-socket.t | 2 +- t/023-rewrite/unix-socket.t | 2 +- t/023-rewrite/uthread-exec.t | 2 +- t/023-rewrite/uthread-exit.t | 2 +- t/023-rewrite/uthread-redirect.t | 2 +- t/023-rewrite/uthread-spawn.t | 2 +- t/024-access/auth.t | 2 +- t/024-access/client-abort.t | 2 +- t/024-access/exec.t | 2 +- t/024-access/exit.t | 2 +- t/024-access/mixed.t | 2 +- t/024-access/multi-capture.t | 2 +- t/024-access/on-abort.t | 2 +- t/024-access/redirect.t | 2 +- t/024-access/req-body.t | 2 +- t/024-access/request_body.t | 2 +- t/024-access/sanity.t | 2 +- t/024-access/satisfy.t | 2 +- t/024-access/sleep.t | 2 +- t/024-access/subrequest.t | 2 +- t/024-access/uthread-exec.t | 2 +- t/024-access/uthread-exit.t | 2 +- t/024-access/uthread-redirect.t | 2 +- t/024-access/uthread-spawn.t | 2 +- t/025-codecache.t | 2 +- t/026-mysql.t | 2 +- t/027-multi-capture.t | 2 +- t/028-req-header.t | 2 +- t/029-http-time.t | 2 +- t/030-uri-args.t | 2 +- t/031-post-args.t | 2 +- t/032-iolist.t | 2 +- t/033-ctx.t | 2 +- t/034-match.t | 4 ++-- t/035-gmatch.t | 2 +- t/036-sub.t | 2 +- t/037-gsub.t | 2 +- t/038-match-o.t | 2 +- t/039-sub-o.t | 2 +- t/040-gsub-o.t | 2 +- t/041-header-filter.t | 2 +- t/042-crc32.t | 2 +- t/043-shdict.t | 2 +- t/044-req-body.t | 2 +- t/045-ngx-var.t | 2 +- t/046-hmac.t | 2 +- t/047-match-jit.t | 2 +- t/048-match-dfa.t | 2 +- t/049-gmatch-jit.t | 2 +- t/050-gmatch-dfa.t | 2 +- t/051-sub-jit.t | 2 +- t/052-sub-dfa.t | 2 +- t/053-gsub-jit.t | 2 +- t/054-gsub-dfa.t | 2 +- t/055-subreq-vars.t | 2 +- t/056-flush.t | 2 +- t/057-flush-timeout.t | 2 +- t/058-tcp-socket.t | 2 +- t/059-unix-socket.t | 2 +- t/060-lua-memcached.t | 2 +- t/061-lua-redis.t | 2 +- t/062-count.t | 2 +- t/063-abort.t | 2 +- t/064-pcall.t | 2 +- t/065-tcp-socket-timeout.t | 2 +- t/066-socket-receiveuntil.t | 2 +- t/067-req-socket.t | 2 +- t/068-socket-keepalive.t | 2 +- t/069-null.t | 2 +- t/070-sha1.t | 2 +- t/071-idle-socket.t | 2 +- t/072-conditional-get.t | 2 +- t/073-backtrace.t | 2 +- t/074-prefix-var.t | 2 +- t/075-logby.t | 2 +- t/076-no-postpone.t | 2 +- t/077-sleep.t | 2 +- t/078-hup-vars.t | 2 +- t/079-unused-directives.t | 2 +- t/080-hup-shdict.t | 2 +- t/081-bytecode.t | 2 +- t/082-body-filter.t | 2 +- t/083-bad-sock-self.t | 2 +- t/084-inclusive-receiveuntil.t | 2 +- t/085-if.t | 2 +- t/086-init-by.t | 2 +- t/087-udp-socket.t | 2 +- t/088-req-method.t | 2 +- t/089-phase.t | 4 ++-- t/090-log-socket-errors.t | 2 +- t/091-coroutine.t | 2 +- t/092-eof.t | 2 +- t/093-uthread-spawn.t | 2 +- t/094-uthread-exit.t | 2 +- t/095-uthread-exec.t | 2 +- t/096-uthread-redirect.t | 2 +- t/097-uthread-rewrite.t | 2 +- t/098-uthread-wait.t | 2 +- t/099-c-api.t | 2 +- t/100-client-abort.t | 2 +- t/101-on-abort.t | 2 +- t/102-req-start-time.t | 2 +- t/103-req-http-ver.t | 2 +- t/104-req-raw-header.t | 2 +- t/105-pressure.t | 2 +- t/106-timer.t | 2 +- t/107-timer-errors.t | 2 +- t/108-timer-safe.t | 2 +- t/109-timer-hup.t | 2 +- t/110-etag.t | 2 +- t/111-req-header-ua.t | 2 +- t/112-req-header-conn.t | 2 +- t/113-req-header-cookie.t | 2 +- t/TestNginxLua.pm | 18 ++++++++++++++++++ 153 files changed, 172 insertions(+), 154 deletions(-) create mode 100644 t/TestNginxLua.pm diff --git a/t/000--init.t b/t/000--init.t index d6b009e18d..e2539b64b1 100644 --- a/t/000--init.t +++ b/t/000--init.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(1); diff --git a/t/000-sanity.t b/t/000-sanity.t index a469a394c0..32f4562804 100644 --- a/t/000-sanity.t +++ b/t/000-sanity.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/001-set.t b/t/001-set.t index b608b24654..8bb83570d6 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/002-content.t b/t/002-content.t index 7b6734f77c..d4459ff659 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/003-errors.t b/t/003-errors.t index 89b5a3a82a..5d1e508762 100644 --- a/t/003-errors.t +++ b/t/003-errors.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(1); diff --git a/t/004-require.t b/t/004-require.t index 4f666f9e41..dd52997263 100644 --- a/t/004-require.t +++ b/t/004-require.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #log_level('warn'); diff --git a/t/005-exit.t b/t/005-exit.t index ee8f7c0a13..c201ed4137 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); repeat_each(2); diff --git a/t/006-escape.t b/t/006-escape.t index 636e0fd25f..562fd7fe30 100644 --- a/t/006-escape.t +++ b/t/006-escape.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/007-md5.t b/t/007-md5.t index 71cba8b42f..ddaaa48350 100644 --- a/t/007-md5.t +++ b/t/007-md5.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/008-today.t b/t/008-today.t index e28dce528c..2f501b6812 100644 --- a/t/008-today.t +++ b/t/008-today.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/009-log.t b/t/009-log.t index 17d542b196..808b456d7e 100644 --- a/t/009-log.t +++ b/t/009-log.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/010-request_body.t b/t/010-request_body.t index b14cf59736..3381858bc2 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/011-md5_bin.t b/t/011-md5_bin.t index e2d43db719..85bfc9414a 100644 --- a/t/011-md5_bin.t +++ b/t/011-md5_bin.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/012-now.t b/t/012-now.t index 941d7b679e..d75b06d890 100644 --- a/t/012-now.t +++ b/t/012-now.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/013-base64.t b/t/013-base64.t index 9b12144946..0cf6365c0f 100644 --- a/t/013-base64.t +++ b/t/013-base64.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/014-bugs.t b/t/014-bugs.t index 1970deab1b..486096e057 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/015-status.t b/t/015-status.t index 358b4c54a8..c1836e71ce 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/016-resp-header.t b/t/016-resp-header.t index e81a87da45..0ca9bb665f 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/017-exec.t b/t/017-exec.t index b043360b96..6d58aa08e8 100644 --- a/t/017-exec.t +++ b/t/017-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/018-ndk.t b/t/018-ndk.t index 9910107fdd..e1c9b49de4 100644 --- a/t/018-ndk.t +++ b/t/018-ndk.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/019-const.t b/t/019-const.t index bbddc4f265..838578888d 100644 --- a/t/019-const.t +++ b/t/019-const.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 17768847c2..565d181ef2 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #master_on(); #workers(1); diff --git a/t/021-cookie-time.t b/t/021-cookie-time.t index 139cfa6023..a6f04574e5 100644 --- a/t/021-cookie-time.t +++ b/t/021-cookie-time.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/022-redirect.t b/t/022-redirect.t index 2bc98e65e0..d2564b87d5 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 093fe0e20a..d4af0f2402 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/023-rewrite/exec.t b/t/023-rewrite/exec.t index 9b2050a76e..98b24c6193 100644 --- a/t/023-rewrite/exec.t +++ b/t/023-rewrite/exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 4664b7131d..11aa1335a5 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); diff --git a/t/023-rewrite/mixed.t b/t/023-rewrite/mixed.t index 833824b7d9..8c1ecb98c3 100644 --- a/t/023-rewrite/mixed.t +++ b/t/023-rewrite/mixed.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/multi-capture.t b/t/023-rewrite/multi-capture.t index 004d1d5cf0..4e522c219c 100644 --- a/t/023-rewrite/multi-capture.t +++ b/t/023-rewrite/multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 29eb0a8f3b..e52562b98b 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t index 948a5d5bbd..7f300abcb2 100644 --- a/t/023-rewrite/redirect.t +++ b/t/023-rewrite/redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index 981e723443..017906e5fa 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t index f5695f0f9d..0cb4c9366c 100644 --- a/t/023-rewrite/req-socket.t +++ b/t/023-rewrite/req-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index f46dd530e2..45c6520f5c 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t index 7b8a2f7670..81fcd0f66c 100644 --- a/t/023-rewrite/sanity.t +++ b/t/023-rewrite/sanity.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #no_nginx_manager(); diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index d178c8ab97..c08caa7801 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index a0f3d95f36..7375a48656 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/subrequest.t b/t/023-rewrite/subrequest.t index 0f2b34893b..c0c6495ed5 100644 --- a/t/023-rewrite/subrequest.t +++ b/t/023-rewrite/subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index b7b2b94114..f10189b318 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -16,7 +16,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 8ba8ae6eeb..bd76b9f94a 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/unix-socket.t b/t/023-rewrite/unix-socket.t index d5d477814e..565e222deb 100644 --- a/t/023-rewrite/unix-socket.t +++ b/t/023-rewrite/unix-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index a563716aa1..4fe17d05ee 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index e14b85c5b5..4f31146e85 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t index 9901719369..2716f9901d 100644 --- a/t/023-rewrite/uthread-redirect.t +++ b/t/023-rewrite/uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index fffa96f9dc..01c66d7b2a 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/auth.t b/t/024-access/auth.t index 168c54a8ee..fafd7fa2e8 100644 --- a/t/024-access/auth.t +++ b/t/024-access/auth.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index d995361d40..256bb10aa9 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/024-access/exec.t b/t/024-access/exec.t index 469246599e..8c708a58ae 100644 --- a/t/024-access/exec.t +++ b/t/024-access/exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/024-access/exit.t b/t/024-access/exit.t index a66f9b0e78..2cb1d4af09 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); repeat_each(2); diff --git a/t/024-access/mixed.t b/t/024-access/mixed.t index 2490dfbb34..9bb2a70c97 100644 --- a/t/024-access/mixed.t +++ b/t/024-access/mixed.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/multi-capture.t b/t/024-access/multi-capture.t index 8d0393026f..5f33e4b11c 100644 --- a/t/024-access/multi-capture.t +++ b/t/024-access/multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 134ba10f5b..56b990b0c3 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t index 3ca6c03b9a..2bc2618b94 100644 --- a/t/024-access/redirect.t +++ b/t/024-access/redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index 8ab6452447..539a22791a 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 46e4109113..6ffcbc56d7 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 9354a26f6c..504d56f818 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #log_level('warn'); diff --git a/t/024-access/satisfy.t b/t/024-access/satisfy.t index 5e31c72198..b4ea31a7d8 100644 --- a/t/024-access/satisfy.t +++ b/t/024-access/satisfy.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t index 8ff76e0686..c9d8b0b5bd 100644 --- a/t/024-access/sleep.t +++ b/t/024-access/sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/024-access/subrequest.t b/t/024-access/subrequest.t index c70366ea4c..060836e085 100644 --- a/t/024-access/subrequest.t +++ b/t/024-access/subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 90e4ddcdde..e34acc6416 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 5d19eb6619..5723fb8032 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t index 4bfb84ab1f..3db3562e1b 100644 --- a/t/024-access/uthread-redirect.t +++ b/t/024-access/uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index c7086a88e1..27e0c618c3 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/025-codecache.t b/t/025-codecache.t index e2ddf395ad..97b3f1b036 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/026-mysql.t b/t/026-mysql.t index eedd8886ac..f6ec442d13 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index c649d99f2a..e283e65694 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/028-req-header.t b/t/028-req-header.t index 76604efcf4..e13d01094e 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/029-http-time.t b/t/029-http-time.t index 6c212f721b..019eae5757 100644 --- a/t/029-http-time.t +++ b/t/029-http-time.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/030-uri-args.t b/t/030-uri-args.t index f74980824e..2b1019f7ee 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/031-post-args.t b/t/031-post-args.t index 99122e0a26..e60c735af7 100644 --- a/t/031-post-args.t +++ b/t/031-post-args.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/032-iolist.t b/t/032-iolist.t index 902ee7c965..6afa971a3f 100644 --- a/t/032-iolist.t +++ b/t/032-iolist.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/033-ctx.t b/t/033-ctx.t index 4688541682..53d2e095f0 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/034-match.t b/t/034-match.t index f45eae82c3..8ce5e0edcc 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; -use Test::Nginx::Socket; + +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 3621c9be22..fce6380817 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/036-sub.t b/t/036-sub.t index 297fefc124..b72e3d4b80 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/037-gsub.t b/t/037-gsub.t index 4f325b446a..3c5312ba43 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/038-match-o.t b/t/038-match-o.t index b8f96a6c86..93b2819d54 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/039-sub-o.t b/t/039-sub-o.t index 5b7e573e1d..505ca7f1d8 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/040-gsub-o.t b/t/040-gsub-o.t index 159a26430d..b99bbe4863 100644 --- a/t/040-gsub-o.t +++ b/t/040-gsub-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 4413f1a998..f0276307d4 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/042-crc32.t b/t/042-crc32.t index 659636da4e..25760b852e 100644 --- a/t/042-crc32.t +++ b/t/042-crc32.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/043-shdict.t b/t/043-shdict.t index 814fffad16..958228b577 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/044-req-body.t b/t/044-req-body.t index aae674e67b..b32f70aaa3 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index a5d52a0cfa..6b7ea5d06a 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/046-hmac.t b/t/046-hmac.t index c66dfb48a6..18459b11e5 100644 --- a/t/046-hmac.t +++ b/t/046-hmac.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/047-match-jit.t b/t/047-match-jit.t index 10333ccbe9..01b2297126 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t index a29c20343f..df7ea700d2 100644 --- a/t/048-match-dfa.t +++ b/t/048-match-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t index 4bf131bcfd..8566055bf6 100644 --- a/t/049-gmatch-jit.t +++ b/t/049-gmatch-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index ba57380752..17bbcbd161 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/051-sub-jit.t b/t/051-sub-jit.t index 6e1f6c0f07..e31de37eb5 100644 --- a/t/051-sub-jit.t +++ b/t/051-sub-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index a92bcb6376..7435dfd29c 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/053-gsub-jit.t b/t/053-gsub-jit.t index ff90afc376..6d5fd9dcab 100644 --- a/t/053-gsub-jit.t +++ b/t/053-gsub-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index 2ea1d046a9..8e9adfd133 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/055-subreq-vars.t b/t/055-subreq-vars.t index 07e7d0591a..be897bbadc 100644 --- a/t/055-subreq-vars.t +++ b/t/055-subreq-vars.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/056-flush.t b/t/056-flush.t index 8577056767..672d225f6a 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -5,7 +5,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 4b7b95323f..d09c36bc73 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -17,7 +17,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 6f31e64f6c..61a948b2af 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/059-unix-socket.t b/t/059-unix-socket.t index 63ddb71c74..bf5005bb26 100644 --- a/t/059-unix-socket.t +++ b/t/059-unix-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/060-lua-memcached.t b/t/060-lua-memcached.t index 588746bb2f..af22281375 100644 --- a/t/060-lua-memcached.t +++ b/t/060-lua-memcached.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t index c1f2363628..e27208df9d 100644 --- a/t/061-lua-redis.t +++ b/t/061-lua-redis.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/062-count.t b/t/062-count.t index a027c2a17a..55b338a88b 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/063-abort.t b/t/063-abort.t index a1e683bbdc..bcc7672a04 100644 --- a/t/063-abort.t +++ b/t/063-abort.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/064-pcall.t b/t/064-pcall.t index e6e7eaeabe..5e544a0f5d 100644 --- a/t/064-pcall.t +++ b/t/064-pcall.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 09953e2d0e..69e4285175 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -16,7 +16,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 2570a9382b..91da15ba49 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 542e4e13e4..374a1a1611 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 408fe94caa..f50c255b29 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(2); diff --git a/t/069-null.t b/t/069-null.t index b50b4389d8..9cb0d55a27 100644 --- a/t/069-null.t +++ b/t/069-null.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/070-sha1.t b/t/070-sha1.t index 3b1d3a0c92..3bb068635c 100644 --- a/t/070-sha1.t +++ b/t/070-sha1.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index db9fde19e5..3aba6d8a46 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t index 285fe14dd8..f9f8383edc 100644 --- a/t/072-conditional-get.t +++ b/t/072-conditional-get.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/073-backtrace.t b/t/073-backtrace.t index 26656576cc..e05081fcd1 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/074-prefix-var.t b/t/074-prefix-var.t index 25d027e9bb..de5f8ad91b 100644 --- a/t/074-prefix-var.t +++ b/t/074-prefix-var.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/075-logby.t b/t/075-logby.t index a4d22b7a89..91a90efa14 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/076-no-postpone.t b/t/076-no-postpone.t index 346ae93492..4d8ca4a406 100644 --- a/t/076-no-postpone.t +++ b/t/076-no-postpone.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/077-sleep.t b/t/077-sleep.t index faafc5c630..0884dcf8c8 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/078-hup-vars.t b/t/078-hup-vars.t index 8aad5cddf9..3e12db5f96 100644 --- a/t/078-hup-vars.t +++ b/t/078-hup-vars.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_on(); diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t index bc00cae1bd..dab7bb8f4d 100644 --- a/t/079-unused-directives.t +++ b/t/079-unused-directives.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/080-hup-shdict.t b/t/080-hup-shdict.t index 5aa142a772..8f25047c56 100644 --- a/t/080-hup-shdict.t +++ b/t/080-hup-shdict.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_process_enabled(1); diff --git a/t/081-bytecode.t b/t/081-bytecode.t index 5cba575546..3fd1fb544b 100644 --- a/t/081-bytecode.t +++ b/t/081-bytecode.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 7fe3eae900..e6fc6212b2 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t index 37b65ef2ed..32e1ccc6dd 100644 --- a/t/083-bad-sock-self.t +++ b/t/083-bad-sock-self.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index ad56bdb163..bc9a388931 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/085-if.t b/t/085-if.t index 1323a48171..230c9d4bb1 100644 --- a/t/085-if.t +++ b/t/085-if.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/086-init-by.t b/t/086-init-by.t index 215bb69c3a..b22771e2a6 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 3b1891d442..9558bdb709 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/088-req-method.t b/t/088-req-method.t index 6b54ba20e8..727f317633 100644 --- a/t/088-req-method.t +++ b/t/088-req-method.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/089-phase.t b/t/089-phase.t index 5a28f596e2..ecf81dec8d 100644 --- a/t/089-phase.t +++ b/t/089-phase.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; -use Test::Nginx::Socket; + +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/090-log-socket-errors.t b/t/090-log-socket-errors.t index 3f3e594c83..815397e0b8 100644 --- a/t/090-log-socket-errors.t +++ b/t/090-log-socket-errors.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 92eab69288..4dc4c21217 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/092-eof.t b/t/092-eof.t index f05fd63f16..2a9e438bad 100644 --- a/t/092-eof.t +++ b/t/092-eof.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 376dba5b0b..44e1b62e2e 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 88a24507cd..62496ef686 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 1a28861df0..4e9ef230d9 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 0a655d74ab..2ae32c3798 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t index bb3b724a66..7ed5cd206c 100644 --- a/t/097-uthread-rewrite.t +++ b/t/097-uthread-rewrite.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 8155653a12..87d0c7a690 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/099-c-api.t b/t/099-c-api.t index 28b35eaf4f..d2bbf79f39 100644 --- a/t/099-c-api.t +++ b/t/099-c-api.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/100-client-abort.t b/t/100-client-abort.t index e1b3761e70..ec508f1450 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 819539fc98..cbaf28813e 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t index 8f3110bad9..2a897d2c8b 100644 --- a/t/102-req-start-time.t +++ b/t/102-req-start-time.t @@ -2,7 +2,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t index 126f00a1bb..a7f1273734 100644 --- a/t/103-req-http-ver.t +++ b/t/103-req-http-ver.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index cc1a145181..a8615d7423 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/105-pressure.t b/t/105-pressure.t index ba516b0998..4dde8da2eb 100644 --- a/t/105-pressure.t +++ b/t/105-pressure.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/106-timer.t b/t/106-timer.t index 8285305100..7e5f0b22b4 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t index c51611b956..8763029220 100644 --- a/t/107-timer-errors.t +++ b/t/107-timer-errors.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t index 8b4fb553db..6cc2b0346e 100644 --- a/t/108-timer-safe.t +++ b/t/108-timer-safe.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 0443c3c35b..5202010d61 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; diff --git a/t/110-etag.t b/t/110-etag.t index c2fc04c937..49911db7f4 100644 --- a/t/110-etag.t +++ b/t/110-etag.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/111-req-header-ua.t b/t/111-req-header-ua.t index 4b1d39c4e6..f51c4df448 100644 --- a/t/111-req-header-ua.t +++ b/t/111-req-header-ua.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/112-req-header-conn.t b/t/112-req-header-conn.t index 37f1a2e435..9f189d0383 100644 --- a/t/112-req-header-conn.t +++ b/t/112-req-header-conn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t index 2d11f7491a..21f4027a3e 100644 --- a/t/113-req-header-cookie.t +++ b/t/113-req-header-cookie.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/TestNginxLua.pm b/t/TestNginxLua.pm new file mode 100644 index 0000000000..59580701a0 --- /dev/null +++ b/t/TestNginxLua.pm @@ -0,0 +1,18 @@ +use Test::Nginx::Socket -Base; + +my $code = $ENV{TEST_NGINX_INIT_BY_LUA}; + +if ($code) { + $code =~ s/\\/\\\\/g; + $code =~ s/['"]/\\$&/g; + + Test::Nginx::Socket::set_http_config_filter(sub { + my $config = shift; + unless ($config =~ s{init_by_lua\s*(['"])((?:\\.|.)*)\1\s*;}{init_by_lua $1$code$2$1;}s) { + $config .= "init_by_lua '$code';"; + } + return $config; + }); +} + +1; From 06da40f9b9313a7fb2be363a6922fdf1308096fe Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 23:19:50 -0700 Subject: [PATCH 0116/1981] style: fixed one line's indentation. --- src/ngx_http_lua_regex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 6f9d70c331..d850c8ccde 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1603,8 +1603,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) #else /* LUA_HAVE_PCRE_DFA */ - msg = "at least pcre 6.0 is required for the DFA mode"; - goto error; + msg = "at least pcre 6.0 is required for the DFA mode"; + goto error; #endif /* LUA_HAVE_PCRE_DFA */ From 9cfcb06ba8aec67c40ce789c04ef988d5a215b2e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 8 May 2013 13:08:26 -0700 Subject: [PATCH 0117/1981] bugfix: segmentation fault might happen in nginx 1.4.x when calling ngx.req.set_header on the Cookie request headers because recent versions of nginx no longer always initialize r->headers_in.cookies. thanks Rob W for reporting this issue as #237. --- src/ngx_http_lua_headers_in.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index f3d8341c8b..b3ae70b08a 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -424,6 +424,17 @@ ngx_http_set_cookie_header(ngx_http_request_t *r, dd("clear headers in cookies: %d", (int) r->headers_in.cookies.nelts); } +#if 1 + if (r->headers_in.cookies.nalloc == 0) { + if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, + sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + } +#endif + if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) { return NGX_ERROR; } From 5cd82926fc3fe8b545b2454d305be147d3d937d7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 8 May 2013 17:32:15 -0700 Subject: [PATCH 0118/1981] bugfix: no longer automatically turn underscores (_) to dashes (-) in header names for ngx.req.set_header and ngx.req.clear_header. thanks aviramc for the report. --- src/ngx_http_lua_headers.c | 2 ++ t/028-req-header.t | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 0f30a78ff8..f69a93f7d4 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -631,12 +631,14 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) dd("key: %.*s, len %d", (int) len, p, (int) len); +#if 0 /* replace "_" with "-" */ for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; } } +#endif key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { diff --git a/t/028-req-header.t b/t/028-req-header.t index 76604efcf4..c26c3b94d4 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -12,7 +12,7 @@ repeat_each(2); plan tests => repeat_each() * (2 * blocks() + 14); #no_diff(); -no_long_string(); +#no_long_string(); run_tests(); @@ -120,7 +120,7 @@ Foo: --- config location /bar { rewrite_by_lua ' - ngx.req.set_header("content_length", 2048) + ngx.req.set_header("content-length", 2048) '; echo_read_request_body; echo_request_body; @@ -1246,3 +1246,26 @@ Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) --- no_error_log [error] + + +=== TEST 39: set input header (with underscores in the header name) +--- config + location /req-header { + rewrite_by_lua ' + ngx.req.set_header("foo_bar", "some value"); + '; + proxy_pass http://127.0.0.1:$server_port/back; + } + location = /back { + echo -n $echo_client_request_headers; + } +--- request +GET /req-header +--- response_body eval +"GET /back HTTP/1.0\r +Host: 127.0.0.1:1985\r +Connection: close\r +foo_bar: some value\r +\r +" + From 300b167bd4a0eec87845f5af304e2a604bb4b0b2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 8 May 2013 18:27:09 -0700 Subject: [PATCH 0119/1981] fixed a test that may time out unexpectedly. --- t/065-tcp-socket-timeout.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 09953e2d0e..c1ea6447c2 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -127,6 +127,7 @@ lua tcp socket connect timed out server_tokens off; lua_socket_connect_timeout 102ms; resolver $TEST_NGINX_RESOLVER; + resolver_timeout 1s; location /t { content_by_lua ' local sock = ngx.socket.tcp() From f20bc6610968bc1a6b3a4fb6b6cbb60fd33cb3d2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 7 May 2013 19:27:48 -0700 Subject: [PATCH 0120/1981] added custom test scaffold t::TestNginxLua which subclasses Test::Nginx::Socket. it supports the environment TEST_NGINX_INIT_BY_LUA which can be used to add more custom Lua code to the value of the init_by_lua directive in the nginx configuration. --- t/000--init.t | 2 +- t/000-sanity.t | 2 +- t/001-set.t | 2 +- t/002-content.t | 2 +- t/003-errors.t | 2 +- t/004-require.t | 2 +- t/005-exit.t | 2 +- t/006-escape.t | 2 +- t/007-md5.t | 2 +- t/008-today.t | 2 +- t/009-log.t | 2 +- t/010-request_body.t | 2 +- t/011-md5_bin.t | 2 +- t/012-now.t | 2 +- t/013-base64.t | 2 +- t/014-bugs.t | 2 +- t/015-status.t | 2 +- t/016-resp-header.t | 2 +- t/017-exec.t | 2 +- t/018-ndk.t | 2 +- t/019-const.t | 2 +- t/020-subrequest.t | 2 +- t/021-cookie-time.t | 2 +- t/022-redirect.t | 2 +- t/023-rewrite/client-abort.t | 2 +- t/023-rewrite/exec.t | 2 +- t/023-rewrite/exit.t | 2 +- t/023-rewrite/mixed.t | 2 +- t/023-rewrite/multi-capture.t | 2 +- t/023-rewrite/on-abort.t | 2 +- t/023-rewrite/redirect.t | 2 +- t/023-rewrite/req-body.t | 2 +- t/023-rewrite/req-socket.t | 2 +- t/023-rewrite/request_body.t | 2 +- t/023-rewrite/sanity.t | 2 +- t/023-rewrite/sleep.t | 2 +- t/023-rewrite/socket-keepalive.t | 2 +- t/023-rewrite/subrequest.t | 2 +- t/023-rewrite/tcp-socket-timeout.t | 2 +- t/023-rewrite/tcp-socket.t | 2 +- t/023-rewrite/unix-socket.t | 2 +- t/023-rewrite/uthread-exec.t | 2 +- t/023-rewrite/uthread-exit.t | 2 +- t/023-rewrite/uthread-redirect.t | 2 +- t/023-rewrite/uthread-spawn.t | 2 +- t/024-access/auth.t | 2 +- t/024-access/client-abort.t | 2 +- t/024-access/exec.t | 2 +- t/024-access/exit.t | 2 +- t/024-access/mixed.t | 2 +- t/024-access/multi-capture.t | 2 +- t/024-access/on-abort.t | 2 +- t/024-access/redirect.t | 2 +- t/024-access/req-body.t | 2 +- t/024-access/request_body.t | 2 +- t/024-access/sanity.t | 2 +- t/024-access/satisfy.t | 2 +- t/024-access/sleep.t | 2 +- t/024-access/subrequest.t | 2 +- t/024-access/uthread-exec.t | 2 +- t/024-access/uthread-exit.t | 2 +- t/024-access/uthread-redirect.t | 2 +- t/024-access/uthread-spawn.t | 2 +- t/025-codecache.t | 2 +- t/026-mysql.t | 2 +- t/027-multi-capture.t | 2 +- t/028-req-header.t | 2 +- t/029-http-time.t | 2 +- t/030-uri-args.t | 2 +- t/031-post-args.t | 2 +- t/032-iolist.t | 2 +- t/033-ctx.t | 2 +- t/034-match.t | 4 ++-- t/035-gmatch.t | 2 +- t/036-sub.t | 2 +- t/037-gsub.t | 2 +- t/038-match-o.t | 2 +- t/039-sub-o.t | 2 +- t/040-gsub-o.t | 2 +- t/041-header-filter.t | 2 +- t/042-crc32.t | 2 +- t/043-shdict.t | 2 +- t/044-req-body.t | 2 +- t/045-ngx-var.t | 2 +- t/046-hmac.t | 2 +- t/047-match-jit.t | 2 +- t/048-match-dfa.t | 2 +- t/049-gmatch-jit.t | 2 +- t/050-gmatch-dfa.t | 2 +- t/051-sub-jit.t | 2 +- t/052-sub-dfa.t | 2 +- t/053-gsub-jit.t | 2 +- t/054-gsub-dfa.t | 2 +- t/055-subreq-vars.t | 2 +- t/056-flush.t | 2 +- t/057-flush-timeout.t | 2 +- t/058-tcp-socket.t | 2 +- t/059-unix-socket.t | 2 +- t/060-lua-memcached.t | 2 +- t/061-lua-redis.t | 2 +- t/062-count.t | 2 +- t/063-abort.t | 2 +- t/064-pcall.t | 2 +- t/065-tcp-socket-timeout.t | 2 +- t/066-socket-receiveuntil.t | 2 +- t/067-req-socket.t | 2 +- t/068-socket-keepalive.t | 2 +- t/069-null.t | 2 +- t/070-sha1.t | 2 +- t/071-idle-socket.t | 2 +- t/072-conditional-get.t | 2 +- t/073-backtrace.t | 2 +- t/074-prefix-var.t | 2 +- t/075-logby.t | 2 +- t/076-no-postpone.t | 2 +- t/077-sleep.t | 2 +- t/078-hup-vars.t | 2 +- t/079-unused-directives.t | 2 +- t/080-hup-shdict.t | 2 +- t/081-bytecode.t | 2 +- t/082-body-filter.t | 2 +- t/083-bad-sock-self.t | 2 +- t/084-inclusive-receiveuntil.t | 2 +- t/085-if.t | 2 +- t/086-init-by.t | 2 +- t/087-udp-socket.t | 2 +- t/088-req-method.t | 2 +- t/089-phase.t | 4 ++-- t/090-log-socket-errors.t | 2 +- t/091-coroutine.t | 2 +- t/092-eof.t | 2 +- t/093-uthread-spawn.t | 2 +- t/094-uthread-exit.t | 2 +- t/095-uthread-exec.t | 2 +- t/096-uthread-redirect.t | 2 +- t/097-uthread-rewrite.t | 2 +- t/098-uthread-wait.t | 2 +- t/099-c-api.t | 2 +- t/100-client-abort.t | 2 +- t/101-on-abort.t | 2 +- t/102-req-start-time.t | 2 +- t/103-req-http-ver.t | 2 +- t/104-req-raw-header.t | 2 +- t/105-pressure.t | 2 +- t/106-timer.t | 2 +- t/107-timer-errors.t | 2 +- t/108-timer-safe.t | 2 +- t/109-timer-hup.t | 2 +- t/110-etag.t | 2 +- t/111-req-header-ua.t | 2 +- t/112-req-header-conn.t | 2 +- t/113-req-header-cookie.t | 2 +- t/TestNginxLua.pm | 18 ++++++++++++++++++ 153 files changed, 172 insertions(+), 154 deletions(-) create mode 100644 t/TestNginxLua.pm diff --git a/t/000--init.t b/t/000--init.t index d6b009e18d..e2539b64b1 100644 --- a/t/000--init.t +++ b/t/000--init.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(1); diff --git a/t/000-sanity.t b/t/000-sanity.t index a469a394c0..32f4562804 100644 --- a/t/000-sanity.t +++ b/t/000-sanity.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/001-set.t b/t/001-set.t index b608b24654..8bb83570d6 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/002-content.t b/t/002-content.t index 7b6734f77c..d4459ff659 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/003-errors.t b/t/003-errors.t index 89b5a3a82a..5d1e508762 100644 --- a/t/003-errors.t +++ b/t/003-errors.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(1); diff --git a/t/004-require.t b/t/004-require.t index 4f666f9e41..dd52997263 100644 --- a/t/004-require.t +++ b/t/004-require.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #log_level('warn'); diff --git a/t/005-exit.t b/t/005-exit.t index ee8f7c0a13..c201ed4137 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); repeat_each(2); diff --git a/t/006-escape.t b/t/006-escape.t index 636e0fd25f..562fd7fe30 100644 --- a/t/006-escape.t +++ b/t/006-escape.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/007-md5.t b/t/007-md5.t index 71cba8b42f..ddaaa48350 100644 --- a/t/007-md5.t +++ b/t/007-md5.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/008-today.t b/t/008-today.t index e28dce528c..2f501b6812 100644 --- a/t/008-today.t +++ b/t/008-today.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/009-log.t b/t/009-log.t index 17d542b196..808b456d7e 100644 --- a/t/009-log.t +++ b/t/009-log.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/010-request_body.t b/t/010-request_body.t index b14cf59736..3381858bc2 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/011-md5_bin.t b/t/011-md5_bin.t index e2d43db719..85bfc9414a 100644 --- a/t/011-md5_bin.t +++ b/t/011-md5_bin.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/012-now.t b/t/012-now.t index 941d7b679e..d75b06d890 100644 --- a/t/012-now.t +++ b/t/012-now.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/013-base64.t b/t/013-base64.t index 9b12144946..0cf6365c0f 100644 --- a/t/013-base64.t +++ b/t/013-base64.t @@ -1,6 +1,6 @@ # vim:set ft=perl ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/014-bugs.t b/t/014-bugs.t index 1970deab1b..486096e057 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/015-status.t b/t/015-status.t index 358b4c54a8..c1836e71ce 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/016-resp-header.t b/t/016-resp-header.t index e81a87da45..0ca9bb665f 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/017-exec.t b/t/017-exec.t index b043360b96..6d58aa08e8 100644 --- a/t/017-exec.t +++ b/t/017-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/018-ndk.t b/t/018-ndk.t index 9910107fdd..e1c9b49de4 100644 --- a/t/018-ndk.t +++ b/t/018-ndk.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/019-const.t b/t/019-const.t index bbddc4f265..838578888d 100644 --- a/t/019-const.t +++ b/t/019-const.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 17768847c2..565d181ef2 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #master_on(); #workers(1); diff --git a/t/021-cookie-time.t b/t/021-cookie-time.t index 139cfa6023..a6f04574e5 100644 --- a/t/021-cookie-time.t +++ b/t/021-cookie-time.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/022-redirect.t b/t/022-redirect.t index 2bc98e65e0..d2564b87d5 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 093fe0e20a..d4af0f2402 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/023-rewrite/exec.t b/t/023-rewrite/exec.t index 9b2050a76e..98b24c6193 100644 --- a/t/023-rewrite/exec.t +++ b/t/023-rewrite/exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 4664b7131d..11aa1335a5 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); diff --git a/t/023-rewrite/mixed.t b/t/023-rewrite/mixed.t index 833824b7d9..8c1ecb98c3 100644 --- a/t/023-rewrite/mixed.t +++ b/t/023-rewrite/mixed.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/multi-capture.t b/t/023-rewrite/multi-capture.t index 004d1d5cf0..4e522c219c 100644 --- a/t/023-rewrite/multi-capture.t +++ b/t/023-rewrite/multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 29eb0a8f3b..e52562b98b 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t index 948a5d5bbd..7f300abcb2 100644 --- a/t/023-rewrite/redirect.t +++ b/t/023-rewrite/redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index 981e723443..017906e5fa 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t index f5695f0f9d..0cb4c9366c 100644 --- a/t/023-rewrite/req-socket.t +++ b/t/023-rewrite/req-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index f46dd530e2..45c6520f5c 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t index 7b8a2f7670..81fcd0f66c 100644 --- a/t/023-rewrite/sanity.t +++ b/t/023-rewrite/sanity.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #no_nginx_manager(); diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index d178c8ab97..c08caa7801 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index a0f3d95f36..7375a48656 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/subrequest.t b/t/023-rewrite/subrequest.t index 0f2b34893b..c0c6495ed5 100644 --- a/t/023-rewrite/subrequest.t +++ b/t/023-rewrite/subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index b7b2b94114..f10189b318 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -16,7 +16,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 8ba8ae6eeb..bd76b9f94a 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/unix-socket.t b/t/023-rewrite/unix-socket.t index d5d477814e..565e222deb 100644 --- a/t/023-rewrite/unix-socket.t +++ b/t/023-rewrite/unix-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index a563716aa1..4fe17d05ee 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index e14b85c5b5..4f31146e85 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t index 9901719369..2716f9901d 100644 --- a/t/023-rewrite/uthread-redirect.t +++ b/t/023-rewrite/uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index fffa96f9dc..01c66d7b2a 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/auth.t b/t/024-access/auth.t index 168c54a8ee..fafd7fa2e8 100644 --- a/t/024-access/auth.t +++ b/t/024-access/auth.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index d995361d40..256bb10aa9 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/024-access/exec.t b/t/024-access/exec.t index 469246599e..8c708a58ae 100644 --- a/t/024-access/exec.t +++ b/t/024-access/exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); #repeat_each(1); diff --git a/t/024-access/exit.t b/t/024-access/exit.t index a66f9b0e78..2cb1d4af09 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(20000); repeat_each(2); diff --git a/t/024-access/mixed.t b/t/024-access/mixed.t index 2490dfbb34..9bb2a70c97 100644 --- a/t/024-access/mixed.t +++ b/t/024-access/mixed.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/multi-capture.t b/t/024-access/multi-capture.t index 8d0393026f..5f33e4b11c 100644 --- a/t/024-access/multi-capture.t +++ b/t/024-access/multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 134ba10f5b..56b990b0c3 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t index 3ca6c03b9a..2bc2618b94 100644 --- a/t/024-access/redirect.t +++ b/t/024-access/redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index 8ab6452447..539a22791a 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 46e4109113..6ffcbc56d7 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 9354a26f6c..504d56f818 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #log_level('warn'); diff --git a/t/024-access/satisfy.t b/t/024-access/satisfy.t index 5e31c72198..b4ea31a7d8 100644 --- a/t/024-access/satisfy.t +++ b/t/024-access/satisfy.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t index 8ff76e0686..c9d8b0b5bd 100644 --- a/t/024-access/sleep.t +++ b/t/024-access/sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/024-access/subrequest.t b/t/024-access/subrequest.t index c70366ea4c..060836e085 100644 --- a/t/024-access/subrequest.t +++ b/t/024-access/subrequest.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 90e4ddcdde..e34acc6416 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 5d19eb6619..5723fb8032 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t index 4bfb84ab1f..3db3562e1b 100644 --- a/t/024-access/uthread-redirect.t +++ b/t/024-access/uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index c7086a88e1..27e0c618c3 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/025-codecache.t b/t/025-codecache.t index e2ddf395ad..97b3f1b036 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/026-mysql.t b/t/026-mysql.t index eedd8886ac..f6ec442d13 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index c649d99f2a..e283e65694 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(10); diff --git a/t/028-req-header.t b/t/028-req-header.t index c26c3b94d4..cd11ad76ea 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/029-http-time.t b/t/029-http-time.t index 6c212f721b..019eae5757 100644 --- a/t/029-http-time.t +++ b/t/029-http-time.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/030-uri-args.t b/t/030-uri-args.t index f74980824e..2b1019f7ee 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/031-post-args.t b/t/031-post-args.t index 99122e0a26..e60c735af7 100644 --- a/t/031-post-args.t +++ b/t/031-post-args.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/032-iolist.t b/t/032-iolist.t index 902ee7c965..6afa971a3f 100644 --- a/t/032-iolist.t +++ b/t/032-iolist.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/033-ctx.t b/t/033-ctx.t index 4688541682..53d2e095f0 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/034-match.t b/t/034-match.t index f45eae82c3..8ce5e0edcc 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; -use Test::Nginx::Socket; + +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 3621c9be22..fce6380817 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/036-sub.t b/t/036-sub.t index 297fefc124..b72e3d4b80 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/037-gsub.t b/t/037-gsub.t index 4f325b446a..3c5312ba43 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/038-match-o.t b/t/038-match-o.t index b8f96a6c86..93b2819d54 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/039-sub-o.t b/t/039-sub-o.t index 5b7e573e1d..505ca7f1d8 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/040-gsub-o.t b/t/040-gsub-o.t index 159a26430d..b99bbe4863 100644 --- a/t/040-gsub-o.t +++ b/t/040-gsub-o.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 4413f1a998..f0276307d4 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/042-crc32.t b/t/042-crc32.t index 659636da4e..25760b852e 100644 --- a/t/042-crc32.t +++ b/t/042-crc32.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/043-shdict.t b/t/043-shdict.t index 814fffad16..958228b577 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/044-req-body.t b/t/044-req-body.t index aae674e67b..b32f70aaa3 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index a5d52a0cfa..6b7ea5d06a 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/046-hmac.t b/t/046-hmac.t index c66dfb48a6..18459b11e5 100644 --- a/t/046-hmac.t +++ b/t/046-hmac.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/047-match-jit.t b/t/047-match-jit.t index 10333ccbe9..01b2297126 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/048-match-dfa.t b/t/048-match-dfa.t index a29c20343f..df7ea700d2 100644 --- a/t/048-match-dfa.t +++ b/t/048-match-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/049-gmatch-jit.t b/t/049-gmatch-jit.t index 4bf131bcfd..8566055bf6 100644 --- a/t/049-gmatch-jit.t +++ b/t/049-gmatch-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/050-gmatch-dfa.t b/t/050-gmatch-dfa.t index ba57380752..17bbcbd161 100644 --- a/t/050-gmatch-dfa.t +++ b/t/050-gmatch-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/051-sub-jit.t b/t/051-sub-jit.t index 6e1f6c0f07..e31de37eb5 100644 --- a/t/051-sub-jit.t +++ b/t/051-sub-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/052-sub-dfa.t b/t/052-sub-dfa.t index a92bcb6376..7435dfd29c 100644 --- a/t/052-sub-dfa.t +++ b/t/052-sub-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/053-gsub-jit.t b/t/053-gsub-jit.t index ff90afc376..6d5fd9dcab 100644 --- a/t/053-gsub-jit.t +++ b/t/053-gsub-jit.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/054-gsub-dfa.t b/t/054-gsub-dfa.t index 2ea1d046a9..8e9adfd133 100644 --- a/t/054-gsub-dfa.t +++ b/t/054-gsub-dfa.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/055-subreq-vars.t b/t/055-subreq-vars.t index 07e7d0591a..be897bbadc 100644 --- a/t/055-subreq-vars.t +++ b/t/055-subreq-vars.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/056-flush.t b/t/056-flush.t index 8577056767..672d225f6a 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -5,7 +5,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 4b7b95323f..d09c36bc73 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -17,7 +17,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 6f31e64f6c..61a948b2af 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/059-unix-socket.t b/t/059-unix-socket.t index 63ddb71c74..bf5005bb26 100644 --- a/t/059-unix-socket.t +++ b/t/059-unix-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/060-lua-memcached.t b/t/060-lua-memcached.t index 588746bb2f..af22281375 100644 --- a/t/060-lua-memcached.t +++ b/t/060-lua-memcached.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t index c1f2363628..e27208df9d 100644 --- a/t/061-lua-redis.t +++ b/t/061-lua-redis.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/062-count.t b/t/062-count.t index a027c2a17a..55b338a88b 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/063-abort.t b/t/063-abort.t index a1e683bbdc..bcc7672a04 100644 --- a/t/063-abort.t +++ b/t/063-abort.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/064-pcall.t b/t/064-pcall.t index e6e7eaeabe..5e544a0f5d 100644 --- a/t/064-pcall.t +++ b/t/064-pcall.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; worker_connections(1014); #master_on(); diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index c1ea6447c2..5b9adeaaaf 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -16,7 +16,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 2570a9382b..91da15ba49 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 542e4e13e4..374a1a1611 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 408fe94caa..f50c255b29 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #repeat_each(2); diff --git a/t/069-null.t b/t/069-null.t index b50b4389d8..9cb0d55a27 100644 --- a/t/069-null.t +++ b/t/069-null.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/070-sha1.t b/t/070-sha1.t index 3b1d3a0c92..3bb068635c 100644 --- a/t/070-sha1.t +++ b/t/070-sha1.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index db9fde19e5..3aba6d8a46 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t index 285fe14dd8..f9f8383edc 100644 --- a/t/072-conditional-get.t +++ b/t/072-conditional-get.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/073-backtrace.t b/t/073-backtrace.t index 26656576cc..e05081fcd1 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/074-prefix-var.t b/t/074-prefix-var.t index 25d027e9bb..de5f8ad91b 100644 --- a/t/074-prefix-var.t +++ b/t/074-prefix-var.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/075-logby.t b/t/075-logby.t index a4d22b7a89..91a90efa14 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/076-no-postpone.t b/t/076-no-postpone.t index 346ae93492..4d8ca4a406 100644 --- a/t/076-no-postpone.t +++ b/t/076-no-postpone.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/077-sleep.t b/t/077-sleep.t index faafc5c630..0884dcf8c8 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/078-hup-vars.t b/t/078-hup-vars.t index 8aad5cddf9..3e12db5f96 100644 --- a/t/078-hup-vars.t +++ b/t/078-hup-vars.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_on(); diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t index bc00cae1bd..dab7bb8f4d 100644 --- a/t/079-unused-directives.t +++ b/t/079-unused-directives.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/080-hup-shdict.t b/t/080-hup-shdict.t index 5aa142a772..8f25047c56 100644 --- a/t/080-hup-shdict.t +++ b/t/080-hup-shdict.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); #worker_connections(1014); #master_process_enabled(1); diff --git a/t/081-bytecode.t b/t/081-bytecode.t index 5cba575546..3fd1fb544b 100644 --- a/t/081-bytecode.t +++ b/t/081-bytecode.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 7fe3eae900..e6fc6212b2 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t index 37b65ef2ed..32e1ccc6dd 100644 --- a/t/083-bad-sock-self.t +++ b/t/083-bad-sock-self.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index ad56bdb163..bc9a388931 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/085-if.t b/t/085-if.t index 1323a48171..230c9d4bb1 100644 --- a/t/085-if.t +++ b/t/085-if.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/086-init-by.t b/t/086-init-by.t index 215bb69c3a..b22771e2a6 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 3b1891d442..9558bdb709 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/088-req-method.t b/t/088-req-method.t index 6b54ba20e8..727f317633 100644 --- a/t/088-req-method.t +++ b/t/088-req-method.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/089-phase.t b/t/089-phase.t index 5a28f596e2..ecf81dec8d 100644 --- a/t/089-phase.t +++ b/t/089-phase.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use lib 'lib'; -use Test::Nginx::Socket; + +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/090-log-socket-errors.t b/t/090-log-socket-errors.t index 3f3e594c83..815397e0b8 100644 --- a/t/090-log-socket-errors.t +++ b/t/090-log-socket-errors.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 92eab69288..4dc4c21217 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; repeat_each(2); diff --git a/t/092-eof.t b/t/092-eof.t index f05fd63f16..2a9e438bad 100644 --- a/t/092-eof.t +++ b/t/092-eof.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 376dba5b0b..44e1b62e2e 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 88a24507cd..62496ef686 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 1a28861df0..4e9ef230d9 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 0a655d74ab..2ae32c3798 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t index bb3b724a66..7ed5cd206c 100644 --- a/t/097-uthread-rewrite.t +++ b/t/097-uthread-rewrite.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 8155653a12..87d0c7a690 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/099-c-api.t b/t/099-c-api.t index 28b35eaf4f..d2bbf79f39 100644 --- a/t/099-c-api.t +++ b/t/099-c-api.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/100-client-abort.t b/t/100-client-abort.t index e1b3761e70..ec508f1450 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 819539fc98..cbaf28813e 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = <<_EOC_; diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t index 8f3110bad9..2a897d2c8b 100644 --- a/t/102-req-start-time.t +++ b/t/102-req-start-time.t @@ -2,7 +2,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/103-req-http-ver.t b/t/103-req-http-ver.t index 126f00a1bb..a7f1273734 100644 --- a/t/103-req-http-ver.t +++ b/t/103-req-http-ver.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/104-req-raw-header.t b/t/104-req-raw-header.t index cc1a145181..a8615d7423 100644 --- a/t/104-req-raw-header.t +++ b/t/104-req-raw-header.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/105-pressure.t b/t/105-pressure.t index ba516b0998..4dde8da2eb 100644 --- a/t/105-pressure.t +++ b/t/105-pressure.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/106-timer.t b/t/106-timer.t index 8285305100..7e5f0b22b4 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t index c51611b956..8763029220 100644 --- a/t/107-timer-errors.t +++ b/t/107-timer-errors.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t index 8b4fb553db..6cc2b0346e 100644 --- a/t/108-timer-safe.t +++ b/t/108-timer-safe.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; use t::StapThread; our $GCScript = $t::StapThread::GCScript; diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 0443c3c35b..5202010d61 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -13,7 +13,7 @@ BEGIN { } use lib 'lib'; -use Test::Nginx::Socket $SkipReason ? (skip_all => $SkipReason) : (); +use t::TestNginxLua $SkipReason ? (skip_all => $SkipReason) : (); use t::StapThread; diff --git a/t/110-etag.t b/t/110-etag.t index c2fc04c937..49911db7f4 100644 --- a/t/110-etag.t +++ b/t/110-etag.t @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_on(); diff --git a/t/111-req-header-ua.t b/t/111-req-header-ua.t index 4b1d39c4e6..f51c4df448 100644 --- a/t/111-req-header-ua.t +++ b/t/111-req-header-ua.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/112-req-header-conn.t b/t/112-req-header-conn.t index 37f1a2e435..9f189d0383 100644 --- a/t/112-req-header-conn.t +++ b/t/112-req-header-conn.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/113-req-header-cookie.t b/t/113-req-header-cookie.t index 2d11f7491a..21f4027a3e 100644 --- a/t/113-req-header-cookie.t +++ b/t/113-req-header-cookie.t @@ -1,7 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; -use Test::Nginx::Socket; +use t::TestNginxLua; #worker_connections(1014); #master_process_enabled(1); diff --git a/t/TestNginxLua.pm b/t/TestNginxLua.pm new file mode 100644 index 0000000000..59580701a0 --- /dev/null +++ b/t/TestNginxLua.pm @@ -0,0 +1,18 @@ +use Test::Nginx::Socket -Base; + +my $code = $ENV{TEST_NGINX_INIT_BY_LUA}; + +if ($code) { + $code =~ s/\\/\\\\/g; + $code =~ s/['"]/\\$&/g; + + Test::Nginx::Socket::set_http_config_filter(sub { + my $config = shift; + unless ($config =~ s{init_by_lua\s*(['"])((?:\\.|.)*)\1\s*;}{init_by_lua $1$code$2$1;}s) { + $config .= "init_by_lua '$code';"; + } + return $config; + }); +} + +1; From bd679f20ef7e89fd2200f34617dd5e72752b6f18 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 8 May 2013 21:37:51 -0700 Subject: [PATCH 0121/1981] refactor: save the ngx_log_t pointer instead of the ngx_http_request_t pointer in ngx_http_lua_script_engine_t. this will make the new FFI-based Lua API easier to implement. --- src/ngx_http_lua_script.c | 6 +++--- src/ngx_http_lua_script.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_script.c b/src/ngx_http_lua_script.c index ede04de0ba..228e3a80d8 100644 --- a/src/ngx_http_lua_script.c +++ b/src/ngx_http_lua_script.c @@ -122,7 +122,7 @@ ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj, ngx_memzero(&e, sizeof(ngx_http_lua_script_engine_t)); - e.request = r; + e.log = r->connection->log; e.ncaptures = count * 2; e.captures = cap; e.captures_data = subj->data; @@ -382,7 +382,7 @@ ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e) e->ip += sizeof(ngx_http_lua_script_copy_code_t) + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0, "lua script copy: \"%*s\"", e->pos - p, p); } @@ -462,7 +462,7 @@ ngx_http_lua_script_copy_capture_code(ngx_http_lua_script_engine_t *e) e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0, "lua script capture: \"%*s\"", e->pos - pos, pos); } diff --git a/src/ngx_http_lua_script.h b/src/ngx_http_lua_script.h index 3e66afdc27..b6dbcd4d7d 100644 --- a/src/ngx_http_lua_script.h +++ b/src/ngx_http_lua_script.h @@ -53,7 +53,7 @@ typedef struct { unsigned skip:1; - ngx_http_request_t *request; + ngx_log_t *log; } ngx_http_lua_script_engine_t; From 603c7a479672b0f7dd8a189c2ac681179ddb642a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 13 May 2013 18:09:08 -0700 Subject: [PATCH 0122/1981] refactor: made the error messages for replacement template compilation failures less verbose in ngx.re.sub and ngx.re.gsub. --- src/ngx_http_lua_regex.c | 3 +-- t/036-sub.t | 12 ++++++------ t/039-sub-o.t | 12 ++++++------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index d850c8ccde..a4eae2bf9a 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1518,8 +1518,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) lua_pushnil(L); lua_pushnil(L); - lua_pushfstring(L, "bad template for substitution: \"%s\"", - lua_tostring(L, 3)); + lua_pushliteral(L, "failed to compile the replacement template"); return 3; } } diff --git a/t/036-sub.t b/t/036-sub.t index b72e3d4b80..cf65313a53 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -85,7 +85,7 @@ a [b c] [b] [c] [] [] d --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" +error: failed to compile the replacement template --- error_log attempt to use named capturing variable "hello" (named captures not supported yet) @@ -107,7 +107,7 @@ attempt to use named capturing variable "hello" (named captures not supported ye --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" +error: failed to compile the replacement template --- error_log attempt to use named capturing variable "hello" (named captures not supported yet) @@ -145,7 +145,7 @@ attempt to use named capturing variable "hello" (named captures not supported ye --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" +error: failed to compile the replacement template --- error_log the closing bracket in "134" variable is missing @@ -166,7 +166,7 @@ the closing bracket in "134" variable is missing --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" +error: failed to compile the replacement template --- error_log the closing bracket in "134" variable is missing @@ -187,7 +187,7 @@ the closing bracket in "134" variable is missing --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${" +error: failed to compile the replacement template --- error_log lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" @@ -208,7 +208,7 @@ lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [$" +error: failed to compile the replacement template --- error_log lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [$" diff --git a/t/039-sub-o.t b/t/039-sub-o.t index 505ca7f1d8..c08987fc53 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -87,7 +87,7 @@ a [b c] [b] [c] [] [] d --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [$2] [$3] [$hello]" +error: failed to compile the replacement template --- error_log attempt to use named capturing variable "hello" (named captures not supported yet) @@ -111,7 +111,7 @@ attempt to use named capturing variable "hello" (named captures not supported ye --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [$2] [$3] [${hello}]" +error: failed to compile the replacement template --- error_log attempt to use named capturing variable "hello" (named captures not supported yet) @@ -149,7 +149,7 @@ attempt to use named capturing variable "hello" (named captures not supported ye --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134]" +error: failed to compile the replacement template --- error_log the closing bracket in "134" variable is missing @@ -170,7 +170,7 @@ the closing bracket in "134" variable is missing --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${134" +error: failed to compile the replacement template --- error_log the closing bracket in "134" variable is missing @@ -191,7 +191,7 @@ the closing bracket in "134" variable is missing --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [${" +error: failed to compile the replacement template --- error_log lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" @@ -212,7 +212,7 @@ lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [${" --- request GET /re --- response_body -error: bad template for substitution: "[$0] [$1] [${2}] [$3] [$" +error: failed to compile the replacement template --- error_log lua script: invalid capturing variable name found in "[$0] [$1] [${2}] [$3] [$" From f50c7789bc211bf5fd15b07924aea24b8fafcbcd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 14 May 2013 17:14:05 -0700 Subject: [PATCH 0123/1981] bugfix: a test case would fail when TEST_NGINX_PORT was set to port numbers other than 1985. --- t/028-req-header.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/028-req-header.t b/t/028-req-header.t index cd11ad76ea..c49fcfeb78 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -1261,11 +1261,11 @@ Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) } --- request GET /req-header ---- response_body eval -"GET /back HTTP/1.0\r -Host: 127.0.0.1:1985\r +--- response_body_like eval +qr{^GET /back HTTP/1.0\r +Host: 127.0.0.1:\d+\r Connection: close\r foo_bar: some value\r \r -" +$} From 63a9915d33fe7af240bf15655ebdc9553642f617 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 21 May 2013 16:15:48 -0700 Subject: [PATCH 0124/1981] added (passing) tests for use of the $invalid_referer variable in Lua. this requires the patch invalid_referer_hash for the nginx core (for now). thanks Fry-kun for reporting this issue as github #239. --- t/045-ngx-var.t | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- util/build2.sh | 2 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index 6b7ea5d06a..1ab406e273 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -8,10 +8,10 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); -no_long_string(); +#no_long_string(); #master_on(); #workers(2); run_tests(); @@ -103,3 +103,53 @@ GET /test --- response_body value: 32 + + +=== TEST 6: true $invalid_referer variable value in Lua +github issue #239 +--- config + location = /t { + valid_referers www.foo.com; + content_by_lua ' + ngx.say("invalid referer: ", ngx.var.invalid_referer) + ngx.exit(200) + '; + #echo $invalid_referer; + } + +--- request +GET /t +--- more_headers +Referer: http://www.foo.com/ + +--- response_body +invalid referer: + +--- no_error_log +[error] + + + +=== TEST 7: false $invalid_referer variable value in Lua +github issue #239 +--- config + location = /t { + valid_referers www.foo.com; + content_by_lua ' + ngx.say("invalid referer: ", ngx.var.invalid_referer) + ngx.exit(200) + '; + #echo $invalid_referer; + } + +--- request +GET /t +--- more_headers +Referer: http://www.bar.com + +--- response_body +invalid referer: 1 + +--- no_error_log +[error] + diff --git a/util/build2.sh b/util/build2.sh index 13a5fa8fa5..2ecd284959 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -16,6 +16,7 @@ force=$2 #--without-http_autoindex_module \ #--with-cc=gcc46 \ #--with-cc=clang \ + #--without-http_referer_module \ time ngx-build $force $version \ --with-cc-opt="-I$PCRE_INC" \ @@ -30,7 +31,6 @@ time ngx-build $force $version \ --without-http_upstream_ip_hash_module \ --without-http_empty_gif_module \ --without-http_memcached_module \ - --without-http_referer_module \ --without-http_auth_basic_module \ --without-http_userid_module \ --add-module=$home/work/nginx/ngx_http_auth_request_module-0.2 \ From 39151875d709b1e528bad448bf99531cb169f1c7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 23 May 2013 12:21:18 -0700 Subject: [PATCH 0125/1981] updated docs to reflect recent changes. --- README | 16 ++++++++-------- README.markdown | 12 ++++++------ doc/HttpLuaModule.wiki | 12 ++++++------ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README b/README index bcc3535c8f..a3b37ffa63 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.1 - () released on 26 - April 2013. + This document describes ngx_lua v0.8.2 + () released on 23 + May 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -5856,7 +5856,7 @@ Nginx Compatibility * 1.3.x (last tested: 1.3.11) - * 1.2.x (last tested: 1.2.8) + * 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) @@ -5880,7 +5880,7 @@ Installation Alternatively, ngx_lua can be manually compiled into Nginx: - 1. Install LuaJIT 2.0 (Recommended) or Lua 5.1 (Lua 5.2 is *not* + 1. Install LuaJIT 2.0 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the the LuaJIT project website () and Lua 5.1, from the Lua project website (). Some distribution @@ -5897,9 +5897,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' - tar -xzvf nginx-1.2.8.tar.gz - cd nginx-1.2.8/ + wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' + tar -xzvf nginx-1.2.9.tar.gz + cd nginx-1.2.9/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/README.markdown b/README.markdown index 94bf0e634f..8ac18f9c66 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.1](https://github.com/chaoslawful/lua-nginx-module/tags) released on 26 April 2013. +This document describes ngx_lua [v0.8.2](https://github.com/chaoslawful/lua-nginx-module/tags) released on 23 May 2013. Synopsis ======== @@ -5208,7 +5208,7 @@ Nginx Compatibility The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.8) +* 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -5226,7 +5226,7 @@ The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, n Alternatively, ngx_lua can be manually compiled into Nginx: -1. Install LuaJIT 2.0 (Recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. +1. Install LuaJIT 2.0 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](http://github.com/simpl/ngx_devel_kit/tags). 1. Download the latest version of ngx_lua [HERE](http://github.com/chaoslawful/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](http://wiki.nginx.org/HttpLuaModule#Nginx_Compatibility)) @@ -5234,9 +5234,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' - tar -xzvf nginx-1.2.8.tar.gz - cd nginx-1.2.8/ + wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' + tar -xzvf nginx-1.2.9.tar.gz + cd nginx-1.2.9/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f428a7008f..95d98d54ba 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.1] released on 26 April 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.2] released on 23 May 2013. = Synopsis = @@ -5035,7 +5035,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k The latest module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.8) +* 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -5051,7 +5051,7 @@ The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ng Alternatively, ngx_lua can be manually compiled into Nginx: -# Install LuaJIT 2.0 (Recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuajIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. +# Install LuaJIT 2.0 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuajIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [http://github.com/simpl/ngx_devel_kit/tags HERE]. # Download the latest version of ngx_lua [http://github.com/chaoslawful/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) @@ -5059,9 +5059,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.8.tar.gz' - tar -xzvf nginx-1.2.8.tar.gz - cd nginx-1.2.8/ + wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' + tar -xzvf nginx-1.2.9.tar.gz + cd nginx-1.2.9/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From 48067c830c5a52625ca0a459de19a0d688265cae Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 24 May 2013 00:16:25 -0700 Subject: [PATCH 0126/1981] feature: added pure C API for ngx.re.sub and ngx.re.gsub, which is expected to be used by lua-resty-core and etc. --- src/ngx_http_lua_regex.c | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 29e57cd157..d36eec3183 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2187,6 +2187,111 @@ ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) ngx_destroy_pool(re->pool); } + + +int +ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re, + const u_char *replace_data, size_t replace_len) +{ + ngx_int_t rc; + ngx_str_t tpl; + ngx_http_lua_complex_value_t *ctpl; + ngx_http_lua_compile_complex_value_t ccv; + + ctpl = ngx_palloc(re->pool, sizeof(ngx_http_lua_complex_value_t)); + if (ctpl == NULL) { + return NGX_ERROR; + } + + if (replace_len != 0) { + /* copy the string buffer pointed to by tpl.data from Lua VM */ + tpl.data = ngx_palloc(re->pool, replace_len + 1); + if (tpl.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(tpl.data, replace_data, replace_len); + tpl.data[replace_len] = '\0'; + + } else { + tpl.data = (u_char *) replace_data; + } + + tpl.len = replace_len; + + ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t)); + ccv.pool = re->pool; + ccv.log = ngx_cycle->log; + ccv.value = &tpl; + ccv.complex_value = ctpl; + + rc = ngx_http_lua_compile_complex_value(&ccv); + + re->replace = ctpl; + + return rc; +} + + +ngx_http_lua_script_engine_t * +ngx_http_lua_ffi_create_script_engine(void) +{ + return ngx_calloc(sizeof(ngx_http_lua_script_engine_t), ngx_cycle->log); +} + + +void +ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e, + const unsigned char *subj, ngx_http_lua_regex_t *compiled, int count) +{ + e->log = ngx_cycle->log; + e->ncaptures = count * 2; + e->captures = compiled->captures; + e->captures_data = (u_char *) subj; +} + + +void +ngx_http_lua_ffi_destroy_script_engine(ngx_http_lua_script_engine_t *e) +{ + ngx_free(e); +} + + +size_t +ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, + ngx_http_lua_complex_value_t *val) +{ + size_t len; + + ngx_http_lua_script_len_code_pt lcode; + + e->ip = val->lengths; + len = 0; + + while (*(uintptr_t *) e->ip) { + lcode = *(ngx_http_lua_script_len_code_pt *) e->ip; + len += lcode(e); + } + + return len; +} + + +void +ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, + ngx_http_lua_complex_value_t *val, u_char *dst, size_t len) +{ + ngx_http_lua_script_code_pt code; + + e->ip = val->values; + e->pos = dst; + + while (*(uintptr_t *) e->ip) { + code = *(ngx_http_lua_script_code_pt *) e->ip; + code(e); + } +} #endif /* NGX_HTTP_LUA_NO_FFI_API */ From b3218be26612282109897651ed5ccd4ab18a9e06 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 30 May 2013 16:20:02 -0700 Subject: [PATCH 0127/1981] bugfix: use of LuaJIT FFI when disabling the Lua code cache would lead to LuaJIT GC assertion failures like "g->gc.total == sizeof(GG_State)" because we unloaded the standard "ffi" module. thanks Ron Gomes for reporting this issue. --- src/ngx_http_lua_cache.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 726d280e34..3c64b9b9e8 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -303,6 +303,12 @@ ngx_http_lua_clear_package_loaded(lua_State *L) break; case 3: +#if 1 + if (ngx_strncmp(p, "ffi", sizeof("ffi") - 1) == 0) { + goto done; + } +#endif + if (ngx_strncmp(p, "bit", sizeof("bit") - 1) == 0) { goto done; } From 34f4042f230e197a608e31278042c32acba6f59f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 7 Jun 2013 12:43:24 -0700 Subject: [PATCH 0128/1981] Revert "bugfix: use of LuaJIT FFI when disabling the Lua code cache would lead to LuaJIT GC assertion failures like "g->gc.total == sizeof(GG_State)" because we unloaded the standard "ffi" module. thanks Ron Gomes for reporting this issue." Preventing unloading "ffi" does not reallys solve the issue here because we can end up with FFI ctype redefinition errors. This reverts commit b3218be26612282109897651ed5ccd4ab18a9e06. --- src/ngx_http_lua_cache.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 3c64b9b9e8..726d280e34 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -303,12 +303,6 @@ ngx_http_lua_clear_package_loaded(lua_State *L) break; case 3: -#if 1 - if (ngx_strncmp(p, "ffi", sizeof("ffi") - 1) == 0) { - goto done; - } -#endif - if (ngx_strncmp(p, "bit", sizeof("bit") - 1) == 0) { goto done; } From f40a50427420708b1b8f6740546b942cb4cfa419 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Jun 2013 22:55:36 -0700 Subject: [PATCH 0129/1981] tests: replaced the domain name "direct.agentzh.org" with "agentzh.org". --- t/023-rewrite/tcp-socket.t | 2 +- t/058-tcp-socket.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index bd76b9f94a..5232f647bb 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -211,7 +211,7 @@ attempt to send data on a closed socket: rewrite_by_lua ' local sock = ngx.socket.tcp() local port = 80 - local ok, err = sock:connect("direct.agentzh.org", port) + local ok, err = sock:connect("agentzh.org", port) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 61a948b2af..8ac85d6c9f 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -207,7 +207,7 @@ attempt to send data on a closed socket: content_by_lua ' local sock = ngx.socket.tcp() local port = 80 - local ok, err = sock:connect("direct.agentzh.org", port) + local ok, err = sock:connect("agentzh.org", port) if not ok then ngx.say("failed to connect: ", err) return From b07a3d3c5f28b790dc5b4daee12b90a612b8ccdb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Jun 2013 16:33:05 -0700 Subject: [PATCH 0130/1981] fixed failing test cases to reflect the multi-value header change in nginx 1.4.1. --- t/016-resp-header.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 0ca9bb665f..eb39fe4dc5 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -626,8 +626,8 @@ Cache-Control: private GET /lua --- response_headers Cache-Control: private, no-store ---- response_body -Cache-Control: private; no-store +--- response_body_like chop +^Cache-Control: private[;,] no-store$ @@ -665,9 +665,9 @@ Cache-Control: no-cache GET /lua --- response_headers Cache-Control: no-cache, blah, foo ---- response_body -Cache-Control: no-cache; blah; foo -Cache-Control: no-cache; blah; foo +--- response_body_like chop +^Cache-Control: no-cache[;,] blah[;,] foo +Cache-Control: no-cache[;,] blah[;,] foo$ From cf4f62a62032bf7ac70a1c9db19c37aab198d370 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Jun 2013 16:33:14 -0700 Subject: [PATCH 0131/1981] updated .gitignore a bit. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ec113d06ac..6624fc5764 100644 --- a/.gitignore +++ b/.gitignore @@ -128,7 +128,7 @@ src/logby.[ch] src/sleep.[ch] a.patch all -build1[0-3] +build1[0-9] g buildroot/ src/headerfilterby.[ch] From 5a880aea932f0465f1fc8a2bc898416a6c51980c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 18 Jun 2013 19:09:14 -0700 Subject: [PATCH 0132/1981] change: made ngx.say/ngx.print/ngx.eof/ngx.flush/ngx.send_headers return nil and a string describing the error in case of most of the common errors (instead of throwing out an exception), and return 1 for success. --- src/ngx_http_lua_output.c | 84 ++++++++++++++++------ src/ngx_http_lua_util.c | 2 +- t/002-content.t | 124 ++++++++++++++++++++++++++++---- t/056-flush.t | 16 ++++- t/072-conditional-get.t | 13 ++-- t/100-client-abort.t | 147 +++++++++++++++++++++++++++++++++++++- 6 files changed, 343 insertions(+), 43 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 327282aabe..7992c91523 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -71,11 +71,15 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) | NGX_HTTP_LUA_CONTEXT_CONTENT); if (r->header_only) { - return 0; + lua_pushnil(L); + lua_pushliteral(L, "header only"); + return 2; } if (ctx->eof) { - return luaL_error(L, "seen eof already"); + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; } nargs = lua_gettop(L); @@ -142,7 +146,8 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) if (size == 0) { /* do nothing for empty strings */ - return 0; + lua_pushinteger(L, 1); + return 1; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; @@ -220,11 +225,13 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) rc = ngx_http_lua_send_chain_link(r, ctx, cl); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to send data through the output filters"); + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; } dd("downstream write: %d, buf len: %d", (int) rc, - (int) (b->last - b->pos)); + (int) (b->last - b->pos)); if (!ctx->out) { #if nginx_version >= 1001004 @@ -235,11 +242,12 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) &ctx->free_bufs, &ctx->busy_bufs, &cl, tag); dd("out lua buf tag: %p, buffered: %x, busy bufs: %p", - &ngx_http_lua_module, (int) r->connection->buffered, - ctx->busy_bufs); + &ngx_http_lua_module, (int) r->connection->buffered, + ctx->busy_bufs); } - return 0; + lua_pushinteger(L, 1); + return 1; } @@ -493,18 +501,24 @@ ngx_http_lua_ngx_flush(lua_State *L) } if (r->header_only) { - return 0; + lua_pushnil(L); + lua_pushliteral(L, "header only"); + return 2; } if (ctx->eof) { - return luaL_error(L, "already seen eof"); + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; } if (ctx->buffering) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua http 1.0 buffering makes ngx.flush() a no-op"); - return 0; + lua_pushnil(L); + lua_pushliteral(L, "buffering"); + return 2; } if (ctx->flush_buf) { @@ -514,7 +528,7 @@ ngx_http_lua_ngx_flush(lua_State *L) dd("allocating new flush buf"); buf = ngx_calloc_buf(r->pool); if (buf == NULL) { - return luaL_error(L, "memory allocation error"); + return luaL_error(L, "out of memory"); } buf->flush = 1; @@ -533,8 +547,12 @@ ngx_http_lua_ngx_flush(lua_State *L) rc = ngx_http_lua_send_chain_link(r, ctx, cl); + dd("send chain: %d", (int) rc); + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to send chain link: %d", (int) rc); + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; } dd("wait:%d, rc:%d, buffered:%d", wait, (int) rc, r->connection->buffered); @@ -558,7 +576,9 @@ ngx_http_lua_ngx_flush(lua_State *L) wev = r->connection->write; if (wev->ready && wev->delayed) { - return 0; + lua_pushnil(L); + lua_pushliteral(L, "delayed"); + return 2; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -571,7 +591,10 @@ ngx_http_lua_ngx_flush(lua_State *L) if (wev->timer_set) { ngx_del_timer(wev); } - return luaL_error(L, "connection broken"); + + lua_pushnil(L); + lua_pushliteral(L, "connection broken"); + return 2; } coctx->cleanup = ngx_http_lua_flush_cleanup; @@ -583,7 +606,8 @@ ngx_http_lua_ngx_flush(lua_State *L) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua flush asynchronously"); - return 0; + lua_pushinteger(L, 1); + return 1; } @@ -615,6 +639,12 @@ ngx_http_lua_ngx_eof(lua_State *L) return luaL_error(L, "no ctx found"); } + if (ctx->eof) { + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; + } + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -622,13 +652,18 @@ ngx_http_lua_ngx_eof(lua_State *L) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send eof"); - rc = ngx_http_lua_send_chain_link(r, ctx, NULL/*indicate last_buf*/); + rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); + + dd("send chain: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to send eof buf"); + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; } - return 0; + lua_pushinteger(L, 1); + return 1; } @@ -658,6 +693,7 @@ ngx_http_lua_inject_output_api(lua_State *L) static int ngx_http_lua_ngx_send_headers(lua_State *L) { + ngx_int_t rc; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; @@ -683,10 +719,16 @@ ngx_http_lua_ngx_send_headers(lua_State *L) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send headers"); - ngx_http_lua_send_header_if_needed(r, ctx); + rc = ngx_http_lua_send_header_if_needed(r, ctx); + if (rc == NGX_ERROR || rc > NGX_OK) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; + } } - return 0; + lua_pushinteger(L, 1); + return 1; } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 7a8aad43f1..868dd852bc 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -472,7 +472,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, } if (!ctx->headers_set && ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } if (!ctx->headers_set) { diff --git a/t/002-content.t b/t/002-content.t index d4459ff659..89b42fccea 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 15); #no_diff(); #no_long_string(); @@ -23,12 +23,19 @@ __DATA__ location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'ngx.print("Hello, Lua!\\n")'; + content_by_lua ' + local ok, err = ngx.print("Hello, Lua!\\n") + if not ok then + ngx.log(ngx.ERR, "print failed: ", err) + end + '; } --- request GET /lua --- response_body Hello, Lua! +--- no_error_log +[error] @@ -38,14 +45,25 @@ Hello, Lua! # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! content_by_lua ' - ngx.say("Hello, Lua!") - ngx.say("Yay! ", 123)'; + local ok, err = ngx.say("Hello, Lua!") + if not ok then + ngx.log(ngx.ERR, "say failed: ", err) + return + end + local ok, err = ngx.say("Yay! ", 123) + if not ok then + ngx.log(ngx.ERR, "say failed: ", err) + return + end + '; } --- request GET /say --- response_body Hello, Lua! Yay! 123 +--- no_error_log +[error] @@ -424,7 +442,11 @@ type: foo/bar #echo "hello, world"; content_by_lua ' ngx.header["Set-Cookie"] = {"a", "hello, world", "foo"} - ngx.eof() + local ok, err = ngx.eof() + if not ok then + ngx.log(ngx.ERR, "eof failed: ", err) + return + end '; } @@ -442,6 +464,8 @@ GET /lua type: table len: 3 value: a|hello, world|foo +--- no_error_log +[error] @@ -521,14 +545,29 @@ hello, world location /lua { content_by_lua ' ngx.say("Hi") - ngx.eof() - ngx.eof() + + local ok, err = ngx.eof() + if not ok then + ngx.log(ngx.WARN, "eof failed: ", err) + return + end + + ok, err = ngx.eof() + if not ok then + ngx.log(ngx.WARN, "eof failed: ", err) + return + end + '; } --- request GET /lua --- response_body Hi +--- no_error_log +[error] +--- error_log +eof failed: seen eof @@ -590,7 +629,9 @@ HEAD /lua location /lua { # NOTE: the newline escape sequence must be double-escaped, as nginx config # parser will unescape first! - content_by_lua 'ngx.print("Hello, Lua!\\n")'; + content_by_lua ' + ngx.print("Hello, Lua!\\n") + '; } --- request HEAD /lua HTTP/1.0 @@ -605,17 +646,74 @@ HEAD /lua HTTP/1.0 location /lua { content_by_lua ' ngx.say(ngx.headers_sent) - ngx.flush() + local ok, err = ngx.flush() + if not ok then + ngx.log(ngx.WARN, "failed to flush: ", err) + return + end ngx.say(ngx.headers_sent) '; } --- request HEAD /lua --- response_body +--- no_error_log +[error] +--- error_log +failed to flush: header only + + + +=== TEST 34: HEAD & ngx.say +--- config + location /lua { + content_by_lua ' + ngx.send_headers() + local ok, err = ngx.say(ngx.headers_sent) + if not ok then + ngx.log(ngx.WARN, "failed to say: ", err) + return + end + '; + } +--- request +HEAD /lua +--- response_body +--- no_error_log +[error] +--- error_log +failed to say: header only + + + +=== TEST 35: ngx.eof before ngx.say +--- config + location /lua { + content_by_lua ' + local ok, err = ngx.eof() + if not ok then + ngx.log(ngx.ERR, "eof failed: ", err) + return + end + + ok, err = ngx.say(ngx.headers_sent) + if not ok then + ngx.log(ngx.WARN, "failed to say: ", err) + return + end + '; + } +--- request +GET /lua +--- response_body +--- no_error_log +[error] +--- error_log +failed to say: seen eof -=== TEST 34: headers_sent + GET +=== TEST 36: headers_sent + GET --- config location /lua { content_by_lua ' @@ -635,7 +733,7 @@ true -=== TEST 35: HTTP 1.0 response with Content-Length +=== TEST 37: HTTP 1.0 response with Content-Length --- config location /lua { content_by_lua ' @@ -664,7 +762,7 @@ world -=== TEST 36: ngx.print table arguments (github issue #54) +=== TEST 38: ngx.print table arguments (github issue #54) --- config location /t { content_by_lua 'ngx.print({10, {0, 5}, 15}, 32)'; @@ -676,7 +774,7 @@ world -=== TEST 37: ngx.say table arguments (github issue #54) +=== TEST 39: ngx.say table arguments (github issue #54) --- config location /t { content_by_lua 'ngx.say({10, {0, "5"}, 15}, 32)'; diff --git a/t/056-flush.t b/t/056-flush.t index 672d225f6a..25900573b8 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -14,7 +14,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 44; +plan tests => repeat_each() * 45; #no_diff(); no_long_string(); @@ -27,7 +27,11 @@ __DATA__ location /test { content_by_lua ' ngx.say("hello, world") - ngx.flush(true) + local ok, err = ngx.flush(true) + if not ok then + ngx.log(ngx.ERR, "flush failed: ", err) + return + end ngx.say("hiya") '; } @@ -36,6 +40,8 @@ GET /test --- response_body hello, world hiya +--- no_error_log +[error] --- error_log lua reuse free buf memory 13 >= 5 @@ -47,7 +53,11 @@ lua reuse free buf memory 13 >= 5 location /test { content_by_lua ' ngx.say("hello, world") - ngx.flush(false) + local ok, err = ngx.flush(false) + if not ok then + ngx.log(ngx.ERR, "flush failed: ", err) + return + end ngx.say("hiya") '; } diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t index f9f8383edc..52b0708ab1 100644 --- a/t/072-conditional-get.t +++ b/t/072-conditional-get.t @@ -13,7 +13,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 1); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -66,7 +66,10 @@ If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT #if_modified_since before; content_by_lua ' ngx.header.last_modified = "Thu, 10 May 2012 07:50:48 GMT" - ngx.say("hello") + local ok, err = ngx.say("hello") + if not ok then + ngx.log(ngx.WARN, "say failed: ", err) + end '; } --- request @@ -77,11 +80,13 @@ If-Unmodified-Since: Thu, 10 May 2012 07:50:47 GMT --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -terminate 1: fail +terminate 1: ok delete thread 1 --- response_body_like: 412 Precondition Failed --- error_code: 412 --- error_log -failed to send data through the output filters +say failed: nginx output filter error +--- no_error_log +[error] diff --git a/t/100-client-abort.t b/t/100-client-abort.t index ec508f1450..169efe9528 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 1); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -921,3 +921,148 @@ lua req cleanup [error] [alert] + + +=== TEST 27: ngx.say +--- config + location /t { + postpone_output 1; + content_by_lua ' + ngx.sleep(0.2) + local ok, err = ngx.say("hello") + if not ok then + ngx.log(ngx.WARN, "say failed: ", err) + return + end + '; + } +--- request +GET /t + +--- wait: 0.2 +--- timeout: 0.1 +--- abort +--- ignore_response +--- no_error_log +[error] +[alert] +--- error_log +say failed: nginx output filter error + + + +=== TEST 28: ngx.print +--- config + location /t { + postpone_output 1; + content_by_lua ' + ngx.sleep(0.2) + local ok, err = ngx.print("hello") + if not ok then + ngx.log(ngx.WARN, "print failed: ", err) + return + end + '; + } +--- request +GET /t + +--- wait: 0.2 +--- timeout: 0.1 +--- abort +--- ignore_response +--- no_error_log +[error] +[alert] +--- error_log +print failed: nginx output filter error + + + +=== TEST 29: ngx.send_headers +--- config + location /t { + postpone_output 1; + content_by_lua ' + ngx.sleep(0.2) + local ok, err = ngx.send_headers() + if not ok then + ngx.log(ngx.WARN, "send headers failed: ", err) + return + end + ngx.log(ngx.WARN, "send headers succeeded") + '; + } +--- request +GET /t + +--- wait: 0.2 +--- timeout: 0.1 +--- abort +--- ignore_response +--- no_error_log +[error] +[alert] +--- error_log +send headers succeeded + + + +=== TEST 30: ngx.flush +--- config + location /t { + #postpone_output 1; + content_by_lua ' + ngx.say("hello") + ngx.sleep(0.2) + local ok, err = ngx.flush() + if not ok then + ngx.log(ngx.WARN, "flush failed: ", err) + return + end + ngx.log(ngx.WARN, "flush succeeded") + '; + } +--- request +GET /t + +--- wait: 0.2 +--- timeout: 0.1 +--- abort +--- ignore_response +--- no_error_log +[error] +[alert] +--- error_log +flush succeeded + + + +=== TEST 31: ngx.eof +--- config + location /t { + postpone_output 1; + content_by_lua ' + ngx.sleep(0.2) + local ok, err = ngx.eof() + if not ok then + ngx.log(ngx.WARN, "eof failed: ", err) + return + end + ngx.log(ngx.WARN, "eof succeeded") + '; + } +--- request +GET /t + +--- wait: 0.2 +--- timeout: 0.1 +--- abort +--- ignore_response +--- no_error_log +[error] +[alert] +eof succeeded +--- error_log +eof failed: nginx output filter error + From ff9580dd3527cf1c2de1523a32186fc97c761555 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 18 Jun 2013 22:47:37 -0700 Subject: [PATCH 0133/1981] bugfix: ngx.flush(true) might not return 1 on success. --- src/ngx_http_lua_output.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 7992c91523..040c2de1bb 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -745,7 +745,10 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) ctx->cur_co_ctx->cleanup = NULL; - rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); + /* push the return value 1 */ + lua_pushinteger(ctx->cur_co_ctx->co, 1); + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 1); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); From d8aa2fedacd057dbf79e6d3091cce8e27b15d79e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 20 Jun 2013 16:02:01 -0700 Subject: [PATCH 0134/1981] updated docs to reflect recent changes. --- README | 44 ++++++++++++++++++++++++++++++------------ README.markdown | 33 +++++++++++++++++++++---------- doc/HttpLuaModule.wiki | 34 ++++++++++++++++++++++---------- 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/README b/README index a3b37ffa63..27faa0347b 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.2 - () released on 23 - May 2013. + This document describes ngx_lua v0.8.3 + () released on 20 + June 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -257,6 +257,12 @@ Directives to to reload the config file are to send a "HUP" signal or to restart Nginx. + Also, Lua files which are loaded by "dofile" or "loadfile" in + *_by_lua_file will never be cached. To ensure code caching, you can + either use the init_by_lua or init_by_lua_file directives to load all + such files or just make these Lua files true Lua modules and load them + via "require". + The ngx_lua module does not currently support the "stat" mode available with the Apache "mod_lua" module but this is planned for implementation in the future. @@ -2741,7 +2747,7 @@ Nginx API for Lua to the same size value in client_max_body_size. Note that calling this function instead of using "ngx.var.request_body" - or "ngx.var.echo_request-body" is more efficient because it can save one + or "ngx.var.echo_request_body" is more efficient because it can save one dynamic memory allocation and one data copy. This function was first introduced in the "v0.3.1rc17" release. @@ -3036,12 +3042,15 @@ Nginx API for Lua call, i.e., "return ngx.redirect(...)", so as to be more explicit. ngx.send_headers - syntax: *ngx.send_headers()* + syntax: *ok, err = ngx.send_headers()* context: *rewrite_by_lua*, access_by_lua*, content_by_lua** Explicitly send out the response headers. + Since "v0.8.3" this function returns 1 on success, or returns "nil" and + a string describing the error otherwise. + Note that there is normally no need to manually send out response headers as ngx_lua will automatically send headers out before content is output with ngx.say or ngx.print or when content_by_lua exits normally. @@ -3057,7 +3066,7 @@ Nginx API for Lua This API was first introduced in ngx_lua v0.3.1rc6. ngx.print - syntax: *ngx.print(...)* + syntax: *ok, err = ngx.print(...)* context: *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -3065,6 +3074,9 @@ Nginx API for Lua response headers have not been sent, this function will send headers out first and then output body data. + Since "v0.8.3" this function returns 1 on success, or returns "nil" and + a string describing the error otherwise. + Lua "nil" values will output "nil" strings and Lua boolean values will output "true" and "false" literal strings respectively. @@ -3098,7 +3110,7 @@ Nginx API for Lua the data yourself in Lua and save the calls. ngx.say - syntax: *ngx.say(...)* + syntax: *ok, err = ngx.say(...)* context: *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -3128,7 +3140,7 @@ Nginx API for Lua file in the Nginx source tree. ngx.flush - syntax: *ngx.flush(wait?)* + syntax: *ok, err = ngx.flush(wait?)* context: *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -3154,6 +3166,9 @@ Nginx API for Lua Note that "ngx.flush" is non functional when in the HTTP 1.0 output buffering mode. See HTTP 1.0 support. + Since "v0.8.3" this function returns 1 on success, or returns "nil" and + a string describing the error otherwise. + ngx.exit syntax: *ngx.exit(status)* @@ -3202,7 +3217,7 @@ Nginx API for Lua hint to others reading the code. ngx.eof - syntax: *ngx.eof()* + syntax: *ok, err = ngx.eof()* context: *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -3235,6 +3250,9 @@ Nginx API for Lua proxy_ignore_client_abort on; + Since "v0.8.3" this function returns 1 on success, or returns "nil" and + a string describing the error otherwise. + ngx.sleep syntax: *ngx.sleep(seconds)* @@ -5854,6 +5872,8 @@ Typical Uses Nginx Compatibility The latest module is compatible with the following versions of Nginx: + * 1.4.x (last tested: 1.4.1) + * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) @@ -5897,9 +5917,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' - tar -xzvf nginx-1.2.9.tar.gz - cd nginx-1.2.9/ + wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' + tar -xzvf nginx-1.4.1.tar.gz + cd nginx-1.4.1/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/README.markdown b/README.markdown index 8ac18f9c66..626015fac1 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.2](https://github.com/chaoslawful/lua-nginx-module/tags) released on 23 May 2013. +This document describes ngx_lua [v0.8.3](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 June 2013. Synopsis ======== @@ -247,6 +247,10 @@ cached because only the Nginx config file parser can correctly parse the `nginx. file and the only ways to to reload the config file are to send a `HUP` signal or to restart Nginx. +Also, Lua files which are loaded by `dofile` or `loadfile` +in *_by_lua_file will never be cached. To ensure code caching, you can either use the [init_by_lua](http://wiki.nginx.org/HttpLuaModule#init_by_lua) +or [init_by_lua_file](http://wiki.nginx.org/HttpLuaModule#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules and load them via `require`. + The ngx_lua module does not currently support the `stat` mode available with the Apache `mod_lua` module but this is planned for implementation in the future. @@ -2559,7 +2563,7 @@ If the request body has been read into disk files, try calling the [ngx.req.get_ To force in-memory request bodies, try setting [client_body_buffer_size](http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size) to the same size value in [client_max_body_size](http://wiki.nginx.org/HttpCoreModule#client_max_body_size). -Note that calling this function instead of using `ngx.var.request_body` or `ngx.var.echo_request-body` is more efficient because it can save one dynamic memory allocation and one data copy. +Note that calling this function instead of using `ngx.var.request_body` or `ngx.var.echo_request_body` is more efficient because it can save one dynamic memory allocation and one data copy. This function was first introduced in the `v0.3.1rc17` release. @@ -2819,12 +2823,14 @@ This method call terminates the current request's processing and never returns. ngx.send_headers ---------------- -**syntax:** *ngx.send_headers()* +**syntax:** *ok, err = ngx.send_headers()* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Explicitly send out the response headers. +Since `v0.8.3` this function returns `1` on success, or returns `nil` and a string describing the error otherwise. + Note that there is normally no need to manually send out response headers as ngx_lua will automatically send headers out before content is output with [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) or [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print) or when [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) exits normally. @@ -2840,12 +2846,14 @@ This API was first introduced in ngx_lua v0.3.1rc6. ngx.print --------- -**syntax:** *ngx.print(...)* +**syntax:** *ok, err = ngx.print(...)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Emits arguments concatenated to the HTTP client (as response body). If response headers have not been sent, this function will send headers out first and then output body data. +Since `v0.8.3` this function returns `1` on success, or returns `nil` and a string describing the error otherwise. + Lua `nil` values will output `"nil"` strings and Lua boolean values will output `"true"` and `"false"` literal strings respectively. Nested arrays of strings are permitted and the elements in the arrays will be sent one by one: @@ -2875,7 +2883,7 @@ Please note that both `ngx.print` and [ngx.say](http://wiki.nginx.org/HttpLuaMod ngx.say ------- -**syntax:** *ngx.say(...)* +**syntax:** *ok, err = ngx.say(...)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -2897,7 +2905,7 @@ There is a hard coded `2048` byte limitation on error message lengths in the Ngi ngx.flush --------- -**syntax:** *ngx.flush(wait?)* +**syntax:** *ok, err = ngx.flush(wait?)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -2911,6 +2919,8 @@ When `ngx.flush(true)` is called immediately after [ngx.print](http://wiki.nginx Note that `ngx.flush` is non functional when in the HTTP 1.0 output buffering mode. See [HTTP 1.0 support](http://wiki.nginx.org/HttpLuaModule#HTTP_1.0_support). +Since `v0.8.3` this function returns `1` on success, or returns `nil` and a string describing the error otherwise. + ngx.exit -------- **syntax:** *ngx.exit(status)* @@ -2959,7 +2969,7 @@ It is recommended, though not necessary, to combine the `return` statement with ngx.eof ------- -**syntax:** *ngx.eof()* +**syntax:** *ok, err = ngx.eof()* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** @@ -2984,6 +2994,8 @@ But if you create subrequests to access other locations configured by Nginx upst proxy_ignore_client_abort on; +Since `v0.8.3` this function returns `1` on success, or returns `nil` and a string describing the error otherwise. + ngx.sleep --------- **syntax:** *ngx.sleep(seconds)* @@ -5207,6 +5219,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: +* 1.4.x (last tested: 1.4.1) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) @@ -5234,9 +5247,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' - tar -xzvf nginx-1.2.9.tar.gz - cd nginx-1.2.9/ + wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' + tar -xzvf nginx-1.4.1.tar.gz + cd nginx-1.4.1/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 95d98d54ba..047af2ca14 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.2] released on 23 May 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.3] released on 20 June 2013. = Synopsis = @@ -235,6 +235,11 @@ cached because only the Nginx config file parser can correctly parse the n file and the only ways to to reload the config file are to send a HUP signal or to restart Nginx. +Also, Lua files which are loaded by dofile or loadfile +in *_by_lua_file will never be cached. To ensure code caching, you can either use the [[#init_by_lua|init_by_lua]] +or [[#init-by_lua_file|init_by_lua_file]] directives to load all such files or just make these Lua files true Lua modules +and load them via require. + The ngx_lua module does not currently support the stat mode available with the Apache mod_lua module but this is planned for implementation in the future. @@ -2483,7 +2488,7 @@ If the request body has been read into disk files, try calling the [[#ngx.req.ge To force in-memory request bodies, try setting [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] to the same size value in [[HttpCoreModule#client_max_body_size|client_max_body_size]]. -Note that calling this function instead of using ngx.var.request_body or ngx.var.echo_request-body is more efficient because it can save one dynamic memory allocation and one data copy. +Note that calling this function instead of using ngx.var.request_body or ngx.var.echo_request_body is more efficient because it can save one dynamic memory allocation and one data copy. This function was first introduced in the v0.3.1rc17 release. @@ -2733,12 +2738,14 @@ URI arguments can be specified as well, for example: This method call terminates the current request's processing and never returns. It is recommended to combine the return statement with this call, i.e., return ngx.redirect(...), so as to be more explicit. == ngx.send_headers == -'''syntax:''' ''ngx.send_headers()'' +'''syntax:''' ''ok, err = ngx.send_headers()'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' Explicitly send out the response headers. +Since v0.8.3 this function returns 1 on success, or returns nil and a string describing the error otherwise. + Note that there is normally no need to manually send out response headers as ngx_lua will automatically send headers out before content is output with [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] or when [[#content_by_lua|content_by_lua]] exits normally. @@ -2752,12 +2759,14 @@ Returns true if the response headers have been sent (by ngx_lua), a This API was first introduced in ngx_lua v0.3.1rc6. == ngx.print == -'''syntax:''' ''ngx.print(...)'' +'''syntax:''' ''ok, err = ngx.print(...)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' Emits arguments concatenated to the HTTP client (as response body). If response headers have not been sent, this function will send headers out first and then output body data. +Since v0.8.3 this function returns 1 on success, or returns nil and a string describing the error otherwise. + Lua nil values will output "nil" strings and Lua boolean values will output "true" and "false" literal strings respectively. Nested arrays of strings are permitted and the elements in the arrays will be sent one by one: @@ -2786,7 +2795,7 @@ This is an asynchronous call and will return immediately without waiting for all Please note that both ngx.print and [[#ngx.say|ngx.say]] will always invoke the whole Nginx output body filter chain, which is an expensive operation. So be careful when calling either of these two in a tight loop; buffer the data yourself in Lua and save the calls. == ngx.say == -'''syntax:''' ''ngx.say(...)'' +'''syntax:''' ''ok, err = ngx.say(...)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' @@ -2806,7 +2815,7 @@ The log_level argument can take constants like ngx.ERR There is a hard coded 2048 byte limitation on error message lengths in the Nginx core. This limit includes trailing newlines and leading time stamps. If the message size exceeds this limit, Nginx will truncate the message text accordingly. This limit can be manually modified by editing the NGX_MAX_ERROR_STR macro definition in the src/core/ngx_log.h file in the Nginx source tree. == ngx.flush == -'''syntax:''' ''ngx.flush(wait?)'' +'''syntax:''' ''ok, err = ngx.flush(wait?)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' @@ -2820,6 +2829,8 @@ When ngx.flush(true) is called immediately after [[#ngx.print|ngx.p Note that ngx.flush is non functional when in the HTTP 1.0 output buffering mode. See [[#HTTP 1.0 support|HTTP 1.0 support]]. +Since v0.8.3 this function returns 1 on success, or returns nil and a string describing the error otherwise. + == ngx.exit == '''syntax:''' ''ngx.exit(status)'' @@ -2866,7 +2877,7 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con It is recommended, though not necessary, to combine the return statement with this call, i.e., return ngx.exit(...), to give a visual hint to others reading the code. == ngx.eof == -'''syntax:''' ''ngx.eof()'' +'''syntax:''' ''ok, err = ngx.eof()'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' @@ -2891,6 +2902,8 @@ But if you create subrequests to access other locations configured by Nginx upst proxy_ignore_client_abort on; +Since v0.8.3 this function returns 1 on success, or returns nil and a string describing the error otherwise. + == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' @@ -5034,6 +5047,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: +* 1.4.x (last tested: 1.4.1) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) @@ -5059,9 +5073,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.9.tar.gz' - tar -xzvf nginx-1.2.9.tar.gz - cd nginx-1.2.9/ + wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' + tar -xzvf nginx-1.4.1.tar.gz + cd nginx-1.4.1/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From 5a0bb76e6654bfefd85a55ce1eb9f6a8d79efed0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 1 Jul 2013 17:49:52 -0700 Subject: [PATCH 0135/1981] optimize: avoided use of the nginx request objects in ngx.escape_uri, ngx.unescape_uri, ngx.quote_sql_str, ngx.decode_base64, ngx.encode_base64, and ngx.decode_args. --- src/ngx_http_lua_args.c | 9 +++--- src/ngx_http_lua_args.h | 3 +- src/ngx_http_lua_string.c | 68 +-------------------------------------- 3 files changed, 6 insertions(+), 74 deletions(-) diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index 523f25505b..a101dd9cb4 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -131,7 +131,7 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { last = buf + r->args.len; - retval = ngx_http_lua_parse_args(r, L, buf, last, max); + retval = ngx_http_lua_parse_args(L, buf, last, max); ngx_pfree(r->pool, buf); @@ -221,7 +221,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) last = buf + len; - retval = ngx_http_lua_parse_args(r, L, buf, last, max); + retval = ngx_http_lua_parse_args(L, buf, last, max); ngx_pfree(r->pool, buf); @@ -230,8 +230,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) int -ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, - u_char *last, int max) +ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) { u_char *p, *q; u_char *src, *dst; @@ -309,7 +308,7 @@ ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, } if (max > 0 && ++count == max) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua hit query args limit %d", max); return 1; diff --git a/src/ngx_http_lua_args.h b/src/ngx_http_lua_args.h index 142849472a..97d8bcdfcd 100644 --- a/src/ngx_http_lua_args.h +++ b/src/ngx_http_lua_args.h @@ -7,8 +7,7 @@ void ngx_http_lua_inject_req_args_api(lua_State *L); -int ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, - u_char *buf, u_char *last, int max); +int ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max); #endif /* NGX_HTTP_LUA_ARGS */ diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 9775457307..243a33df97 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -107,20 +107,10 @@ ngx_http_lua_inject_string_api(lua_State *L) static int ngx_http_lua_ngx_escape_uri(lua_State *L) { - ngx_http_request_t *r; size_t len, dlen; uintptr_t escape; u_char *src, *dst; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } @@ -147,20 +137,10 @@ ngx_http_lua_ngx_escape_uri(lua_State *L) static int ngx_http_lua_ngx_unescape_uri(lua_State *L) { - ngx_http_request_t *r; size_t len, dlen; u_char *p; u_char *src, *dst; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } @@ -185,20 +165,10 @@ ngx_http_lua_ngx_unescape_uri(lua_State *L) static int ngx_http_lua_ngx_quote_sql_str(lua_State *L) { - ngx_http_request_t *r; size_t len, dlen, escape; u_char *p; u_char *src, *dst; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } @@ -232,8 +202,6 @@ ngx_http_lua_ngx_quote_sql_str(lua_State *L) *p++ = '\''; if (p != dst + dlen) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "ngx.quote_sql_str: buffer error"); return NGX_ERROR; } @@ -429,18 +397,8 @@ ngx_http_lua_ngx_sha1_bin(lua_State *L) static int ngx_http_lua_ngx_decode_base64(lua_State *L) { - ngx_http_request_t *r; ngx_str_t p, src; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } @@ -464,8 +422,6 @@ ngx_http_lua_ngx_decode_base64(lua_State *L) lua_pushnil(L); } - ngx_pfree(r->pool, p.data); - return 1; } @@ -473,18 +429,8 @@ ngx_http_lua_ngx_decode_base64(lua_State *L) static int ngx_http_lua_ngx_encode_base64(lua_State *L) { - ngx_http_request_t *r; ngx_str_t p, src; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument"); } @@ -505,8 +451,6 @@ ngx_http_lua_ngx_encode_base64(lua_State *L) lua_pushlstring(L, (char *) p.data, p.len); - ngx_pfree(r->pool, p.data); - return 1; } @@ -576,7 +520,6 @@ ngx_http_lua_ngx_encode_args(lua_State *L) { static int ngx_http_lua_ngx_decode_args(lua_State *L) { - ngx_http_request_t *r; u_char *buf; u_char *tmp; size_t len = 0; @@ -599,21 +542,12 @@ ngx_http_lua_ngx_decode_args(lua_State *L) { max = NGX_HTTP_LUA_MAX_ARGS; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - tmp = lua_newuserdata(L, len); ngx_memcpy(tmp, buf, len); lua_createtable(L, 0, 4); - return ngx_http_lua_parse_args(r, L, tmp, tmp + len, max); + return ngx_http_lua_parse_args(L, tmp, tmp + len, max); } From f05ef37b995a93978cfbfcfb1e91e612d277e7a4 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 1 Jul 2013 18:20:18 -0700 Subject: [PATCH 0136/1981] optimize: avoided use of the nginx request objects in ngx.encode_args. --- src/ngx_http_lua_string.c | 13 +------------ src/ngx_http_lua_util.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 243a33df97..2b2d68a3bb 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -493,7 +493,6 @@ ngx_http_lua_ngx_crc32_long(lua_State *L) static int ngx_http_lua_ngx_encode_args(lua_State *L) { - ngx_http_request_t *r; ngx_str_t args; if (lua_gettop(L) != 1) { @@ -501,19 +500,9 @@ ngx_http_lua_ngx_encode_args(lua_State *L) { lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - luaL_checktype(L, 1, LUA_TTABLE); - - ngx_http_lua_process_args_option(r, L, 1, &args); - + ngx_http_lua_process_args_option(NULL, L, 1, &args); lua_pushlstring(L, (char *) args.data, args.len); - - ngx_pfree(r->pool, args.data); - return 1; } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 868dd852bc..fc6657ac64 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2300,10 +2300,15 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, dd("len 1: %d", (int) len); - p = ngx_palloc(r->pool, len); - if (p == NULL) { - luaL_error(L, "out of memory"); - return; + if (r) { + p = ngx_palloc(r->pool, len); + if (p == NULL) { + luaL_error(L, "out of memory"); + return; + } + + } else { + p = lua_newuserdata(L, len); } args->data = p; From fe27fc2a4c68d59688a73e2c8812709318af9854 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 1 Jul 2013 19:03:42 -0700 Subject: [PATCH 0137/1981] updated README.markdown to reflect recent changes in docs. --- README.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 626015fac1..6229c19757 100644 --- a/README.markdown +++ b/README.markdown @@ -247,9 +247,10 @@ cached because only the Nginx config file parser can correctly parse the `nginx. file and the only ways to to reload the config file are to send a `HUP` signal or to restart Nginx. -Also, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file will never be cached. To ensure code caching, you can either use the [init_by_lua](http://wiki.nginx.org/HttpLuaModule#init_by_lua) -or [init_by_lua_file](http://wiki.nginx.org/HttpLuaModule#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules and load them via `require`. +Also, Lua files which are loaded by `dofile` or `loadfile` +in *_by_lua_file will never be cached. To ensure code caching, you can either use the [init_by_lua](http://wiki.nginx.org/HttpLuaModule#init_by_lua) +or [init_by_lua_file](http://wiki.nginx.org/HttpLuaModule#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules +and load them via `require`. The ngx_lua module does not currently support the `stat` mode available with the Apache `mod_lua` module but this is planned for implementation in the future. From d9e3e8feea40387898bee972dc6cdf904f010b85 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 1 Jul 2013 19:04:34 -0700 Subject: [PATCH 0138/1981] refactor: added inline functions ngx_http_lua_get_req and ngx_http_lua_set_req to eliminate code duplication when storing or fetching the nginx request object from the lua global variable table. --- src/ngx_http_lua_accessby.c | 5 +-- src/ngx_http_lua_api.c | 9 +---- src/ngx_http_lua_args.c | 18 ++------- src/ngx_http_lua_bodyfilterby.c | 4 +- src/ngx_http_lua_contentby.c | 5 +-- src/ngx_http_lua_control.c | 24 ++---------- src/ngx_http_lua_coroutine.c | 24 ++---------- src/ngx_http_lua_ctx.c | 16 ++------ src/ngx_http_lua_headerfilterby.c | 4 +- src/ngx_http_lua_headers.c | 36 +++--------------- src/ngx_http_lua_log.c | 10 +---- src/ngx_http_lua_logby.c | 4 +- src/ngx_http_lua_misc.c | 13 ++----- src/ngx_http_lua_ndk.c | 6 +-- src/ngx_http_lua_output.c | 23 ++---------- src/ngx_http_lua_phase.c | 5 +-- src/ngx_http_lua_regex.c | 24 ++---------- src/ngx_http_lua_req_body.c | 62 +++++++++---------------------- src/ngx_http_lua_req_method.c | 12 +----- src/ngx_http_lua_rewriteby.c | 5 +-- src/ngx_http_lua_setby.c | 4 +- src/ngx_http_lua_sleep.c | 8 ++-- src/ngx_http_lua_socket_tcp.c | 57 ++++++++++++---------------- src/ngx_http_lua_socket_udp.c | 34 ++++++----------- src/ngx_http_lua_subrequest.c | 6 +-- src/ngx_http_lua_time.c | 6 +-- src/ngx_http_lua_timer.c | 13 +------ src/ngx_http_lua_uri.c | 8 ++-- src/ngx_http_lua_uthread.c | 12 +----- src/ngx_http_lua_util.c | 12 +----- src/ngx_http_lua_util.h | 23 ++++++++++++ src/ngx_http_lua_variable.c | 12 +----- 32 files changed, 138 insertions(+), 366 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 84c9aaa3ac..4cd584db88 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -257,10 +257,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ - lua_pushlightuserdata(co, &ngx_http_lua_request_key); - lua_pushlightuserdata(co, r); - lua_rawset(co, LUA_GLOBALSINDEX); - /* }}} */ + ngx_http_lua_set_req(co, r); /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index e0c50cdfb7..9597fee468 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -25,14 +25,7 @@ ngx_http_lua_get_global_state(ngx_conf_t *cf) ngx_http_request_t * ngx_http_lua_get_request(lua_State *L) { - ngx_http_request_t *r; - - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - - return r; + return ngx_http_lua_get_req(L); } diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index a101dd9cb4..9be9ff3288 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -33,11 +33,7 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -106,11 +102,7 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { max = NGX_HTTP_LUA_MAX_ARGS; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -166,11 +158,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) max = NGX_HTTP_LUA_MAX_ARGS; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index d9298a5abe..c9d557c82d 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -53,9 +53,7 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_chain_t *in) { /* set nginx request pointer to current lua thread's globals table */ - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_pushlightuserdata(L, r); - lua_rawset(L, LUA_GLOBALSINDEX); + ngx_http_lua_set_req(L, r); lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, in); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 26dff47cb2..5a74169966 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -67,10 +67,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ - lua_pushlightuserdata(co, &ngx_http_lua_request_key); - lua_pushlightuserdata(co, r); - lua_rawset(co, LUA_GLOBALSINDEX); - /* }}} */ + ngx_http_lua_set_req(co, r); ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index b32f438f64..7142481c77 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -69,11 +69,7 @@ ngx_http_lua_ngx_exec(lua_State *L) n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -225,11 +221,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) rc = NGX_HTTP_MOVED_TEMPORARILY; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -301,11 +293,7 @@ ngx_http_lua_ngx_exit(lua_State *L) return luaL_error(L, "expecting one argument"); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -365,11 +353,7 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_co_ctx_t *coctx = NULL; ngx_http_lua_loc_conf_t *llcf; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index d92ed5d16f..10c971086f 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -42,11 +42,7 @@ ngx_http_lua_coroutine_create(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -127,11 +123,7 @@ ngx_http_lua_coroutine_resume(lua_State *L) luaL_argcheck(L, co, 1, "coroutine expected"); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -190,11 +182,7 @@ ngx_http_lua_coroutine_yield(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -310,11 +298,7 @@ ngx_http_lua_coroutine_status(lua_State *L) luaL_argcheck(L, co, 1, "coroutine expected"); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } diff --git a/src/ngx_http_lua_ctx.c b/src/ngx_http_lua_ctx.c index b591729599..7ca1353334 100644 --- a/src/ngx_http_lua_ctx.c +++ b/src/ngx_http_lua_ctx.c @@ -20,13 +20,9 @@ ngx_http_lua_ngx_get_ctx(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { - return luaL_error(L, "no request object found"); + return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -64,13 +60,9 @@ ngx_http_lua_ngx_set_ctx(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { - return luaL_error(L, "no request object found"); + return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index f2a70f9bea..75aad5bbd5 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -47,9 +47,7 @@ static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { /* set nginx request pointer to current lua thread's globals table */ - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_pushlightuserdata(L, r); - lua_rawset(L, LUA_GLOBALSINDEX); + ngx_http_lua_set_req(L, r); /** * we want to create empty environment for current script diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index f69a93f7d4..fb7f557780 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -32,11 +32,7 @@ ngx_http_lua_ngx_req_http_version(lua_State *L) { ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -85,11 +81,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("no req line: %d", (int) no_req_line); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -322,11 +314,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { max = NGX_HTTP_LUA_MAX_HEADERS; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -399,11 +387,7 @@ ngx_http_lua_ngx_header_get(lua_State *L) size_t len; ngx_http_lua_loc_conf_t *llcf; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -455,11 +439,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_uint_t n; ngx_http_lua_loc_conf_t *llcf; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -616,11 +596,7 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) ngx_int_t rc; ngx_uint_t n; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index 3f32531e20..eca3ac78c2 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -36,10 +36,7 @@ ngx_http_lua_ngx_log(lua_State *L) ngx_http_request_t *r; const char *msg; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); if (r && r->connection && r->connection->log) { log = r->connection->log; @@ -77,10 +74,7 @@ ngx_http_lua_print(lua_State *L) ngx_log_t *log; ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); if (r && r->connection && r->connection->log) { log = r->connection->log; diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 08e9a19ca8..3038b255b3 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -36,9 +36,7 @@ static void ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) { /* set nginx request pointer to current lua thread's globals table */ - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_pushlightuserdata(L, r); - lua_rawset(L, LUA_GLOBALSINDEX); + ngx_http_lua_set_req(L, r); /** * we want to create empty environment for current script diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index fecc4b242b..474aa15e5b 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -41,11 +41,7 @@ ngx_http_lua_ngx_get(lua_State *L) size_t len; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -106,17 +102,13 @@ ngx_http_lua_ngx_set(lua_State *L) size_t len; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -141,6 +133,7 @@ ngx_http_lua_ngx_set(lua_State *L) if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_ndk.c b/src/ngx_http_lua_ndk.c index ac9e410fca..c7306a31da 100644 --- a/src/ngx_http_lua_ndk.c +++ b/src/ngx_http_lua_ndk.c @@ -85,11 +85,7 @@ ngx_http_lua_run_set_var_directive(lua_State *L) arg.data = (u_char *) luaL_checklstring(L, 1, &len); arg.len = len; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 040c2de1bb..f58dcada67 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -51,11 +51,7 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) const char *msg; ngx_buf_tag_t tag; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -476,10 +472,7 @@ ngx_http_lua_ngx_flush(lua_State *L) "or 1", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); if (n == 1 && r == r->main) { luaL_checktype(L, 1, LUA_TBOOLEAN); @@ -621,11 +614,7 @@ ngx_http_lua_ngx_eof(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_int_t rc; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -697,11 +686,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index 6b43110941..e0aa4500f0 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -24,10 +24,7 @@ ngx_http_lua_ngx_get_phase(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); /* If we have no request object, assume we are called from the "init" * phase. */ diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index a4eae2bf9a..0aefa2eb6f 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -140,11 +140,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) "but got %d", nargs); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -581,11 +577,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) nargs); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -911,11 +903,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) dd("offset %d, r %p, subj %s", (int) offset, ctx->request, subj.data); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -1220,11 +1208,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) nargs); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 4a61fb72d1..a11075a84e 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -80,11 +80,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) return luaL_error(L, "expecting 0 arguments but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -217,11 +213,7 @@ ngx_http_lua_ngx_req_discard_body(lua_State *L) return luaL_error(L, "expecting 0 arguments but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -254,11 +246,7 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) return luaL_error(L, "expecting 0 arguments but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -325,11 +313,7 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) return luaL_error(L, "expecting 0 arguments but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -379,11 +363,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) body.data = (u_char *) luaL_checklstring(L, 1, &body.len); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -546,10 +526,10 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) return luaL_error(L, "expecting 0 or 1 argument but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_http_lua_check_fake_request(L, r); @@ -646,10 +626,10 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) body.data = (u_char *) luaL_checklstring(L, 1, &body.len); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_http_lua_check_fake_request(L, r); @@ -709,13 +689,9 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) return luaL_error(L, "expecting 0 argument but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { - return luaL_error(L, "no request"); + return luaL_error(L, "no request found"); } ngx_http_lua_check_fake_request(L, r); @@ -841,13 +817,9 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) p = (u_char *) luaL_checklstring(L, 1, &name.len); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { - return luaL_error(L, "request object not found"); + return luaL_error(L, "no request found"); } ngx_http_lua_check_fake_request(L, r); diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index e221913f45..fc64d1498b 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -41,11 +41,7 @@ ngx_http_lua_ngx_req_get_method(lua_State *L) return luaL_error(L, "only one argument expected but got %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -71,11 +67,7 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) method = luaL_checkint(L, 1); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index bd0fd3baae..b678de6f8c 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -255,10 +255,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ - lua_pushlightuserdata(co, &ngx_http_lua_request_key); - lua_pushlightuserdata(co, r); - lua_rawset(co, LUA_GLOBALSINDEX); - /* }}} */ + ngx_http_lua_set_req(co, r); /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 4d158da271..5cd4781669 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -207,9 +207,7 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { /* set nginx request pointer to current lua thread's globals table */ - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_pushlightuserdata(L, r); - lua_rawset(L, LUA_GLOBALSINDEX); + ngx_http_lua_set_req(L, r); lua_pushlightuserdata(L, &ngx_http_lua_setby_nargs_key); lua_pushinteger(L, nargs); diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index ec5499c263..997d9646d5 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -36,10 +36,10 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } delay = luaL_checknumber(L, 1) * 1000; diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 34c6fad1b6..dae1dc7dcf 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -221,11 +221,7 @@ ngx_http_lua_socket_tcp(lua_State *L) lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -282,11 +278,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) "arguments (including the object), but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -1011,10 +1003,10 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) "(including the object), but got %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket calling receive() method"); @@ -1613,10 +1605,10 @@ ngx_http_lua_socket_tcp_send(lua_State *L) "but got %d", lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } luaL_checktype(L, 1, LUA_TTABLE); @@ -1856,10 +1848,10 @@ ngx_http_lua_socket_tcp_close(lua_State *L) "(including the object) but seen %d", lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } luaL_checktype(L, 1, LUA_TTABLE); @@ -2485,10 +2477,10 @@ ngx_http_lua_socket_tcp_receiveuntil(lua_State *L) lua_pop(L, 2); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket calling receiveuntil() method"); @@ -3013,10 +3005,7 @@ ngx_http_lua_req_socket(lua_State *L) lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); if (r != r->main) { return luaL_error(L, "attempt to read the request body in a " @@ -3261,10 +3250,10 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } b = &u->buffer; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 07de29ab8a..2a73818648 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -118,11 +118,7 @@ ngx_http_lua_socket_udp(lua_State *L) lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -182,11 +178,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) "arguments (including the object), but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -733,11 +725,7 @@ ngx_http_lua_socket_udp_send(lua_State *L) "but got %d", lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } @@ -861,10 +849,10 @@ ngx_http_lua_socket_udp_receive(lua_State *L) "(including the object), but got %d", nargs); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket calling receive() method"); @@ -1413,10 +1401,10 @@ ngx_http_lua_socket_udp_close(lua_State *L) "(including the object) but seen %d", lua_gettop(L)); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } luaL_checktype(L, 1, LUA_TTABLE); diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 7b63d0ad05..93e488fdcd 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -155,11 +155,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "at least one subrequest should be specified"); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index bdcc44e0a2..d256870ecd 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -189,11 +189,7 @@ ngx_http_lua_ngx_req_start_time(lua_State *L) { ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 38e9cd85e0..f745e51b75 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -81,11 +81,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } @@ -448,12 +444,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) dd("r connection: %p, log %p", r->connection, r->connection->log); /* save the request in coroutine globals table */ - lua_pushvalue(tctx.co, LUA_GLOBALSINDEX); - lua_pushlightuserdata(tctx.co, &ngx_http_lua_request_key); - lua_pushlightuserdata(tctx.co, r); - lua_rawset(tctx.co, -3); - lua_pop(tctx.co, 1); - /* }}} */ + ngx_http_lua_set_req(tctx.co, r); lmcf->running_timers++; diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index f8d2157b8b..05450f6649 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -42,10 +42,10 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) return luaL_error(L, "expecting 1 argument but seen %d", n); } - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } ngx_http_lua_check_fake_request(L, r); diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 1132bf6141..2ef4ad99b3 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -52,11 +52,7 @@ ngx_http_lua_uthread_spawn(lua_State *L) n = lua_gettop(L); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } @@ -111,11 +107,7 @@ ngx_http_lua_uthread_wait(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx, *sub_coctx; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index fc6657ac64..43ee3b5aa4 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2802,11 +2802,7 @@ ngx_http_lua_param_get(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return 0; } @@ -2835,11 +2831,7 @@ ngx_http_lua_param_set(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return 0; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index b06c383dcf..11a987bdce 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -203,6 +203,29 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) } +static ngx_inline ngx_http_request_t * +ngx_http_lua_get_req(lua_State *L) +{ + ngx_http_request_t *r; + + lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_rawget(L, LUA_GLOBALSINDEX); + r = lua_touserdata(L, -1); + lua_pop(L, 1); + + return r; +} + + +static ngx_inline void +ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) +{ + lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_pushlightuserdata(L, r); + lua_rawset(L, LUA_GLOBALSINDEX); +} + + #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index 20f3d103cf..b7d43fe453 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -60,11 +60,7 @@ ngx_http_lua_var_get(lua_State *L) int *cap; #endif - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } @@ -150,11 +146,7 @@ ngx_http_lua_var_set(lua_State *L) int value_type; const char *msg; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); - lua_rawget(L, LUA_GLOBALSINDEX); - r = lua_touserdata(L, -1); - lua_pop(L, 1); - + r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } From 569cabe17879bf56e33e5a9ea18b3a31a4fddfc0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 1 Jul 2013 19:11:02 -0700 Subject: [PATCH 0139/1981] refactor: no longer store cf->log into the lua registry table because we can directly access the global ngx_cycle->log thing. --- src/ngx_http_lua_initby.c | 3 --- src/ngx_http_lua_log.c | 10 ++-------- src/ngx_http_lua_util.c | 4 ---- src/ngx_http_lua_util.h | 3 --- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index 8fd0eb6d44..72b705648b 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -17,9 +17,6 @@ static int ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status); static int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L); -char ngx_http_lua_cf_log_key; - - int ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L) diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index eca3ac78c2..850b2f99b7 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -42,10 +42,7 @@ ngx_http_lua_ngx_log(lua_State *L) log = r->connection->log; } else { - lua_pushlightuserdata(L, &ngx_http_lua_cf_log_key); - lua_rawget(L, LUA_REGISTRYINDEX); - log = lua_touserdata(L, -1); - lua_pop(L, 1); + log = ngx_cycle->log; } int level = luaL_checkint(L, 1); @@ -80,10 +77,7 @@ ngx_http_lua_print(lua_State *L) log = r->connection->log; } else { - lua_pushlightuserdata(L, &ngx_http_lua_cf_log_key); - lua_rawget(L, LUA_REGISTRYINDEX); - log = lua_touserdata(L, -1); - lua_pop(L, 1); + log = ngx_cycle->log; } return log_wrapper(log, "[lua] ", NGX_LOG_NOTICE, L); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 43ee3b5aa4..908036d9af 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -719,10 +719,6 @@ ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L) lua_newtable(L); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ - - lua_pushlightuserdata(L, &ngx_http_lua_cf_log_key); - lua_pushlightuserdata(L, cf->log); - lua_rawset(L, LUA_REGISTRYINDEX); } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 11a987bdce..cef4a9c0b4 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -35,9 +35,6 @@ extern char ngx_http_lua_socket_pool_key; /* char whose address we use as the key for the nginx request pointer */ extern char ngx_http_lua_request_key; -/* char whose address we use as the key for the nginx config logger */ -extern char ngx_http_lua_cf_log_key; - /* char whose address we use as the key for the coroutine parent relationship */ extern char ngx_http_lua_coroutine_parents_key; From d82196f7fd0f074335ea3434826c303383a5e0f8 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 2 Jul 2013 17:11:07 -0700 Subject: [PATCH 0140/1981] bugfix: t::TestNginxLua: env TEST_NGINX_INIT_BY_LUA would break existing init_by_lua_file directive in the test case. --- t/TestNginxLua.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/TestNginxLua.pm b/t/TestNginxLua.pm index 59580701a0..023d439488 100644 --- a/t/TestNginxLua.pm +++ b/t/TestNginxLua.pm @@ -8,6 +8,9 @@ if ($code) { Test::Nginx::Socket::set_http_config_filter(sub { my $config = shift; + if ($config =~ /init_by_lua_file/) { + return $config; + } unless ($config =~ s{init_by_lua\s*(['"])((?:\\.|.)*)\1\s*;}{init_by_lua $1$code$2$1;}s) { $config .= "init_by_lua '$code';"; } From 5e256f8bf53085498ae0b6fbe51d950de32ea45b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 2 Jul 2013 17:28:32 -0700 Subject: [PATCH 0141/1981] refactor: now we store the nginx request object as a named Lua global variable __ngx_req to help FFI-based Lua code access it. --- src/ngx_http_lua_util.c | 1 - src/ngx_http_lua_util.h | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 908036d9af..a1fa9a2c16 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -58,7 +58,6 @@ char ngx_http_lua_code_cache_key; char ngx_http_lua_ctx_tables_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; -char ngx_http_lua_request_key; char ngx_http_lua_coroutines_key; char ngx_http_lua_req_get_headers_metatable_key; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index cef4a9c0b4..ce699d5849 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -32,9 +32,6 @@ extern char ngx_http_lua_regex_cache_key; * socket connection pool table */ extern char ngx_http_lua_socket_pool_key; -/* char whose address we use as the key for the nginx request pointer */ -extern char ngx_http_lua_request_key; - /* char whose address we use as the key for the coroutine parent relationship */ extern char ngx_http_lua_coroutine_parents_key; @@ -205,7 +202,7 @@ ngx_http_lua_get_req(lua_State *L) { ngx_http_request_t *r; - lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_pushliteral(L, "__ngx_req"); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); @@ -217,7 +214,7 @@ ngx_http_lua_get_req(lua_State *L) static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { - lua_pushlightuserdata(L, &ngx_http_lua_request_key); + lua_pushliteral(L, "__ngx_req"); lua_pushlightuserdata(L, r); lua_rawset(L, LUA_GLOBALSINDEX); } From 25ef1f9426bb5bbbf6181a0f776f855a03c43bab Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 2 Jul 2013 17:38:54 -0700 Subject: [PATCH 0142/1981] feature: added pure C API for ngx.exit, which is expected to be used with LuaJIT FFI (or lua-resty-core in particular). also added coroutine._yield for the original std version of coroutine.yield. --- src/ngx_http_lua_control.c | 62 ++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_coroutine.c | 3 ++ src/ngx_http_lua_util.h | 19 +++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 7142481c77..d92889af6e 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -401,4 +401,66 @@ ngx_http_lua_on_abort(lua_State *L) return 1; } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +int +ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, + size_t *errlen) +{ + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + *errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err; + return NGX_ERROR; + } + + if (ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER, + err, errlen) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->no_abort + && status != NGX_ERROR + && status != NGX_HTTP_CLOSE + && status != NGX_HTTP_REQUEST_TIME_OUT + && status != NGX_HTTP_CLIENT_CLOSED_REQUEST) + { + *errlen = ngx_snprintf(err, *errlen, + "attempt to abort with pending subrequests") + - err; + return NGX_ERROR; + } + + if (ctx->headers_sent + && status >= NGX_HTTP_SPECIAL_RESPONSE + && status != NGX_HTTP_REQUEST_TIME_OUT + && status != NGX_HTTP_CLIENT_CLOSED_REQUEST + && status != NGX_HTTP_CLOSE) + { + if (status != (ngx_int_t) r->headers_out.status) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " + "set status %i via ngx.exit after sending out the " + "response status %ui", status, + r->headers_out.status); + } + + status = NGX_HTTP_OK; + } + + ctx->exit_code = status; + ctx->exited = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exit with code %i", ctx->exit_code); + + return NGX_OK; +} +#endif /* NGX_HTTP_LUA_NO_FFI_API */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 10c971086f..8e70d5dd8e 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -234,6 +234,9 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) lua_getfield(L, -1, "running"); lua_setfield(L, -3, "running"); + lua_getfield(L, -1, "yield"); + lua_setfield(L, -3, "_yield"); + /* pop the old coroutine */ lua_pop(L, 1); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index ce699d5849..45add389a1 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -66,6 +66,25 @@ extern char ngx_http_lua_req_get_headers_metatable_key; } +#ifndef NGX_HTTP_LUA_NO_FFI_API +static ngx_inline ngx_int_t +ngx_http_lua_ffi_check_context(ngx_http_lua_ctx_t *ctx, unsigned flags, + u_char *err, size_t *errlen) +{ + if (!(ctx->context & flags)) { + *errlen = ngx_snprintf(err, *errlen, + "API disabled in the context of %s", + ngx_http_lua_context_name((ctx)->context)) + - err; + + return NGX_DECLINED; + } + + return NGX_OK; +} +#endif + + #define ngx_http_lua_check_fake_request(L, r) \ if ((r)->connection->fd == -1) { \ return luaL_error(L, "API disabled in the current context"); \ From 6977e95185891a7d58d0d65b33643fae84fd1a78 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 8 Jul 2013 16:50:58 -0700 Subject: [PATCH 0143/1981] bugfix: setting ngx.var.VARIABLE could lead to stack buffer over-read in luaL_error when an error happened. --- src/ngx_http_lua_variable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index b7d43fe453..ebaf56f9bd 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -159,9 +159,10 @@ ngx_http_lua_var_set(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); - lowcase = lua_newuserdata(L, len); + lowcase = lua_newuserdata(L, len + 1); hash = ngx_hash_strlow(lowcase, p, len); + lowcase[len] = '\0'; name.len = len; name.data = lowcase; From 4d27348ccb1761c1659707f9c1edadb7044f7832 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 9 Jul 2013 17:00:01 -0700 Subject: [PATCH 0144/1981] bugfix: tcpsock:send("") resulted in the error log alert message "send() returned zero". --- src/ngx_http_lua_socket_tcp.c | 5 +++++ t/058-tcp-socket.t | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index dae1dc7dcf..a3eb86ab7d 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1664,6 +1664,11 @@ ngx_http_lua_socket_tcp_send(lua_State *L) return luaL_argerror(L, 2, msg); } + if (len == 0) { + lua_pushinteger(L, 0); + return 1; + } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 8ac85d6c9f..2fef1032e6 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 95; +plan tests => repeat_each() * 96; our $HtmlDir = html_dir; @@ -1987,6 +1987,7 @@ send(""): 0 close: 1 nil --- no_error_log [error] +[alert] From 4656a290b3d4c7bdc2d5490d418856ac9c629295 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 10 Jul 2013 23:09:09 -0700 Subject: [PATCH 0145/1981] docs: bumped version to 0.8.4; also mentioned Nginx Systemtap Toolkit. --- README | 10 +++++----- README.markdown | 7 ++----- doc/HttpLuaModule.wiki | 6 ++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/README b/README index 27faa0347b..f5544249e9 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.3 - () released on 20 - June 2013. + This document describes ngx_lua v0.8.4 + () released on 10 + July 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -6172,6 +6172,6 @@ See Also * The ngx_openresty bundle () -Translations - * Chinese (still in progress) + * Nginx Systemtap Toolkit + () diff --git a/README.markdown b/README.markdown index 6229c19757..b0759aa6d2 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.3](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 June 2013. +This document describes ngx_lua [v0.8.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 July 2013. Synopsis ======== @@ -5422,8 +5422,5 @@ See Also * [postgres-nginx-module](http://github.com/FRiCKLE/ngx_postgres) * [HttpMemcModule](http://wiki.nginx.org/HttpMemcModule) * [The ngx_openresty bundle](http://openresty.org) - -Translations -============ -* [Chinese](http://wiki.nginx.org/HttpLuaModuleZh) (still in progress) +* [Nginx Systemtap Toolkit](https://github.com/agentzh/nginx-systemtap-toolkit) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 047af2ca14..5c6148b53a 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.3] released on 20 June 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.4] released on 10 July 2013. = Synopsis = @@ -5235,7 +5235,5 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * [http://github.com/FRiCKLE/ngx_postgres postgres-nginx-module] * [[HttpMemcModule]] * [http://openresty.org The ngx_openresty bundle] - -= Translations = -* [[HttpLuaModuleZh|Chinese]] (still in progress) +* [https://github.com/agentzh/nginx-systemtap-toolkit Nginx Systemtap Toolkit] From 76c2427ac56f94f708f8b4ae08874918d99fe53b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 10 Jul 2013 23:18:21 -0700 Subject: [PATCH 0146/1981] test: made the resolver less possible to time out in two test cases. --- t/065-tcp-socket-timeout.t | 2 +- t/087-udp-socket.t | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 5b9adeaaaf..22326ae369 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -127,7 +127,7 @@ lua tcp socket connect timed out server_tokens off; lua_socket_connect_timeout 102ms; resolver $TEST_NGINX_RESOLVER; - resolver_timeout 1s; + resolver_timeout 3s; location /t { content_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 9558bdb709..6540db2a81 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -700,6 +700,7 @@ resolve name done === 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 ' @@ -735,6 +736,7 @@ successfully connected to xxx! --- no_error_log [error] +--- timeout: 5 From a184a9111254a2abf040e713399f5b9f080300ec Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 14 Jul 2013 23:52:16 -0700 Subject: [PATCH 0147/1981] util/build2.sh: default to nginx 1.4.1 now. --- util/build2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/build2.sh b/util/build2.sh index 2ecd284959..77d56fdb7a 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -3,7 +3,7 @@ # this file is mostly meant to be used by the author himself. root=`pwd` -version=${1:-1.2.1} +version=${1:-1.4.1} home=~ force=$2 From fe467e52bc91673780464c379346e5852ac3b163 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 15 Jul 2013 00:07:22 -0700 Subject: [PATCH 0148/1981] bugfix: the ngx.ctx tables would leak memory when ngx.ctx, ngx.exec()/ngx.req.set_uri(uri, true), and log_by_lua were used together in a single location. thanks Guanlan Dai for writing the gdb utils to catch this. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_setby.c | 2 +- src/ngx_http_lua_timer.c | 2 +- src/ngx_http_lua_util.c | 34 +++++---- src/ngx_http_lua_util.h | 4 +- t/033-ctx.t | 110 +++++++++++++++++++++++++++++- 10 files changed, 139 insertions(+), 23 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 4cd584db88..68cc777ef3 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -285,7 +285,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index c9d557c82d..2b07e52545 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -306,7 +306,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 5a74169966..28364617db 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -80,7 +80,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 75aad5bbd5..cb335b89db 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -279,7 +279,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) return NGX_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index b678de6f8c..2f58b6c791 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -283,7 +283,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 5cd4781669..75faad6af5 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -71,7 +71,7 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, return NGX_ERROR; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index f745e51b75..5b6839a571 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -428,7 +428,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) goto abort; } - cln->handler = ngx_http_lua_request_cleanup; + cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a1fa9a2c16..f4bd59661c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -909,16 +909,22 @@ ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r) void -ngx_http_lua_request_cleanup(void *data) +ngx_http_lua_request_cleanup_handler(void *data) +{ + ngx_http_lua_request_cleanup(data, 0 /* forcible */); +} + + +void +ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) { - ngx_http_request_t *r = data; lua_State *L; ngx_http_lua_ctx_t *ctx; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua request cleanup"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua request cleanup: forcible=%d", forcible); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -951,9 +957,9 @@ ngx_http_lua_request_cleanup(void *data) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->log_handler == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua release ngx.ctx"); + if (forcible || llcf->log_handler == NULL) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua release ngx.ctx at ref %d", ctx->ctx_ref); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -1389,7 +1395,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 0); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1447,7 +1453,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 0); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " "user coroutine has no parent"); @@ -2045,7 +2051,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 1 /* forcible */); if (ctx->exec_uri.data[0] == '@') { if (ctx->exec_args.len > 0) { @@ -2150,7 +2156,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 0); if (ctx->buffering && r->headers_out.status) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); @@ -2466,7 +2472,7 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 1 /* forcible */); ngx_http_lua_init_ctx(ctx); return NGX_OK; @@ -3204,7 +3210,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if (ctx->on_abort_co_ctx == NULL) { r->connection->error = 1; - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 0); ngx_http_lua_finalize_request(r, rc); return; } @@ -3217,7 +3223,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { - ngx_http_lua_request_cleanup(r); + ngx_http_lua_request_cleanup(r, 0); ngx_http_lua_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index ce699d5849..b7f7ad27f9 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -104,7 +104,9 @@ void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, void ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r); -void ngx_http_lua_request_cleanup(void *data); +void ngx_http_lua_request_cleanup(ngx_http_request_t *r, int foricible); + +void ngx_http_lua_request_cleanup_handler(void *data); ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int nret); diff --git a/t/033-ctx.t b/t/033-ctx.t index 53d2e095f0..472fccc320 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 1); +plan tests => repeat_each() * (blocks() * 3 + 4); #no_diff(); #no_long_string(); @@ -210,3 +210,111 @@ foo = 3, bar = 4 --- no_error_log [error] + + +=== TEST 9: ngx.ctx leaks with ngx.exec + log_by_lua +--- config + location = /t { + content_by_lua ' + ngx.ctx.foo = 32; + ngx.exec("/f") + '; + log_by_lua 'ngx.log(ngx.WARN, "ctx.foo = ", ngx.ctx.foo)'; + } + location = /f { + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } +--- request +GET /t +--- response_body +nil +--- no_error_log +[error] +ctx.foo = + + + +=== TEST 10: memory leaks with ngx.ctx + ngx.req.set_uri + log_by_lua +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = 32; + ngx.req.set_uri("/f", true) + '; + log_by_lua 'ngx.log(ngx.WARN, "ctx.foo = ", ngx.ctx.foo)'; + } + location = /f { + content_by_lua ' + ngx.say(ngx.ctx.foo) + '; + } +--- request +GET /t +--- response_body +nil +--- no_error_log +[error] +ctx.foo = + + + +=== TEST 11: ngx.ctx + ngx.exit(ngx.ERROR) + log_by_lua +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = 32; + ngx.exit(ngx.ERROR) + '; + log_by_lua 'ngx.log(ngx.WARN, "ngx.ctx = ", ngx.ctx.foo)'; + } +--- request +GET /t +--- ignore_response +--- no_error_log +[error] +--- error_log +ngx.ctx = 32 + + + +=== TEST 12: ngx.ctx + ngx.exit(200) + log_by_lua +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = 32; + ngx.say(ngx.ctx.foo) + ngx.exit(200) + '; + log_by_lua 'ngx.log(ngx.WARN, "ctx.foo = ", ngx.ctx.foo)'; + } +--- request +GET /t +--- response_body +32 +--- no_error_log +[error] +--- error_log +ctx.foo = 32 + + + +=== TEST 13: ngx.ctx + ngx.redirect + log_by_lua +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = 32; + ngx.redirect("/f") + '; + log_by_lua 'ngx.log(ngx.WARN, "ngx.ctx.foo = ", 32)'; + } +--- request +GET /t +--- response_body_like: 302 Found +--- error_code: 302 +--- error_log +ctx.foo = 32 +--- no_error_log +[error] + From 8708f604f584dacc9397dc8006aa0b7df7833e7a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 15 Jul 2013 12:30:31 -0700 Subject: [PATCH 0149/1981] docs: typo fixes in the code sample for body_filter_by_lua. thanks cyberty for reporting this issue as #261. --- README | 2 +- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index f5544249e9..792fecfc5c 100644 --- a/README +++ b/README @@ -938,7 +938,7 @@ Directives # fastcgi_pass/proxy_pass/... header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = {string.len(arg[1]), "\n"}' + body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; } Note that the following API functions are currently disabled within this diff --git a/README.markdown b/README.markdown index b0759aa6d2..1307d90bc3 100644 --- a/README.markdown +++ b/README.markdown @@ -832,7 +832,7 @@ When the Lua code may change the length of the response body, then it is require # fastcgi_pass/proxy_pass/... header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = {string.len(arg[1]), "\n"}' + body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; } diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5c6148b53a..986bb87c56 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -804,7 +804,7 @@ When the Lua code may change the length of the response body, then it is require # fastcgi_pass/proxy_pass/... header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = {string.len(arg[1]), "\n"}' + body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; } From 0aca2046ff048f94e93118f235c99f45c46d8db1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 15 Jul 2013 12:39:02 -0700 Subject: [PATCH 0150/1981] bugfix: when compiling with -DDDEBUG=1, there was a compilation error in ngx_http_lua_uthread.c. thanks tigeryang for the report in #259. --- src/ngx_http_lua_uthread.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 2ef4ad99b3..a93b84c553 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -154,9 +154,9 @@ ngx_http_lua_uthread_wait(lua_State *L) nrets = lua_gettop(sub_coctx->co); - dd("child retval count: %d, %s: %s", n, - luaL_typename(sub_coctx->co, -1), - lua_tostring(sub_coctx->co, -1)); + dd("child retval count: %d, %s: %s", (int) nrets, + luaL_typename(sub_coctx->co, -1), + lua_tostring(sub_coctx->co, -1)); if (nrets) { lua_xmove(sub_coctx->co, L, nrets); From 9d017a21ed7c4c05bd0893be30de9c44286ebf17 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 16 Jul 2013 19:35:04 -0700 Subject: [PATCH 0151/1981] feature: added new directive lua_regex_match_limit for setting PCRE match_limit for regex matching. --- src/ngx_http_lua_common.h | 1 + src/ngx_http_lua_module.c | 12 +++++ src/ngx_http_lua_regex.c | 39 +++++++++++----- t/034-match.t | 80 +++++++++++++++++++++++++++++++++ t/035-gmatch.t | 94 ++++++++++++++++++++++++++++++++++++++- t/036-sub.t | 74 ++++++++++++++++++++++++++++++ t/037-gsub.t | 75 +++++++++++++++++++++++++++++++ t/047-match-jit.t | 80 +++++++++++++++++++++++++++++++++ 8 files changed, 443 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 4c3b08352d..25cd9a42d5 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -112,6 +112,7 @@ struct ngx_http_lua_main_conf_s { #if (NGX_PCRE) ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; + ngx_int_t regex_match_limit; #endif ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 8e412cf4b8..63d4f7f9eb 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -75,6 +75,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { NGX_HTTP_MAIN_CONF_OFFSET, offsetof(ngx_http_lua_main_conf_t, regex_cache_max_entries), NULL }, + + { ngx_string("lua_regex_match_limit"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_lua_main_conf_t, regex_match_limit), + NULL }, #endif { ngx_string("lua_package_cpath"), @@ -526,6 +533,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) lmcf->regex_cache_max_entries = NGX_CONF_UNSET; + lmcf->regex_match_limit = NGX_CONF_UNSET; #endif lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; @@ -544,6 +552,10 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; } + + if (lmcf->regex_match_limit == NGX_CONF_UNSET) { + lmcf->regex_match_limit = 0; + } #endif if (lmcf->max_pending_timers == NGX_CONF_UNSET) { diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 0aefa2eb6f..b32c2f281f 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -124,7 +124,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) int ovecsize; ngx_uint_t flags; ngx_pool_t *pool, *old_pool; - ngx_http_lua_main_conf_t *lmcf = NULL; + ngx_http_lua_main_conf_t *lmcf; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; int name_entry_size, name_count; @@ -184,8 +184,9 @@ ngx_http_lua_ngx_re_match(lua_State *L) flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (flags & NGX_LUA_RE_COMPILE_ONCE) { - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); @@ -349,6 +350,11 @@ ngx_http_lua_ngx_re_match(lua_State *L) #endif /* LUA_HAVE_PCRE_JIT */ + if (sd && lmcf->regex_match_limit > 0) { + sd->flags |= PCRE_EXTRA_MATCH_LIMIT; + sd->match_limit = lmcf->regex_match_limit; + } + dd("compile done, captures %d", (int) re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { @@ -373,7 +379,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled regex (%d captures) into the cache " "(entries %i)", re_comp.captures, - lmcf ? lmcf->regex_cache_entries : 0); + lmcf->regex_cache_entries); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { @@ -550,7 +556,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) static int ngx_http_lua_ngx_re_gmatch(lua_State *L) { - ngx_http_lua_main_conf_t *lmcf = NULL; + ngx_http_lua_main_conf_t *lmcf; ngx_http_request_t *r; ngx_str_t subj; ngx_str_t pat; @@ -600,8 +606,9 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (flags & NGX_LUA_RE_COMPILE_ONCE) { - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); @@ -764,6 +771,11 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) #endif /* LUA_HAVE_PCRE_JIT */ + if (sd && lmcf->regex_match_limit > 0) { + sd->flags |= PCRE_EXTRA_MATCH_LIMIT; + sd->match_limit = lmcf->regex_match_limit; + } + dd("compile done, captures %d", re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { @@ -785,7 +797,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled regex (%d captures) into the cache " "(entries %i)", re_comp.captures, - lmcf ? lmcf->regex_cache_entries : 0); + lmcf->regex_cache_entries); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { @@ -986,8 +998,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) } if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\"", - (int) rc, subj.data); + msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc); goto error; } @@ -1174,7 +1185,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ngx_str_t pat; ngx_str_t opts; ngx_str_t tpl; - ngx_http_lua_main_conf_t *lmcf = NULL; + ngx_http_lua_main_conf_t *lmcf; ngx_pool_t *pool, *old_pool; const char *msg; ngx_int_t rc; @@ -1254,8 +1265,9 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 4); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (flags & NGX_LUA_RE_COMPILE_ONCE) { - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); @@ -1438,6 +1450,11 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) #endif /* LUA_HAVE_PCRE_JIT */ + if (sd && lmcf->regex_match_limit > 0) { + sd->flags |= PCRE_EXTRA_MATCH_LIMIT; + sd->match_limit = lmcf->regex_match_limit; + } + dd("compile done, captures %d", re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { @@ -1512,7 +1529,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled sub regex (%d captures) into " "the cache (entries %i)", re_comp.captures, - lmcf ? lmcf->regex_cache_entries : 0); + lmcf->regex_cache_entries); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { diff --git a/t/034-match.t b/t/034-match.t index 8ce5e0edcc..f3f69ff8aa 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -1013,3 +1013,83 @@ exec opts: 0 --- no_error_log [error] + + +=== TEST 45: just hit match limit +--- http_config + lua_regex_match_limit 5600; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, err = ngx.re.match(s, re, "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +error: pcre_exec() failed: -8 + + + +=== TEST 46: just not hit match limit +--- http_config + lua_regex_match_limit 5700; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, err = ngx.re.match(s, re, "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +failed to match + diff --git a/t/035-gmatch.t b/t/035-gmatch.t index fce6380817..2a41362fcf 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -736,7 +736,7 @@ error: pcre_compile() failed: missing ) in "(abc" --- request GET /t --- response_body_like chop -error: pcre_exec\(\) failed: -10 on "你.*?" +error: pcre_exec\(\) failed: -10 --- no_error_log [error] @@ -811,3 +811,95 @@ exec opts: 0 --- no_error_log [error] + + +=== TEST 30: just hit match limit +--- http_config + lua_regex_match_limit 5600; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local it, err = ngx.re.gmatch(s, re, "o") +if not it then + ngx.say("failed to gen iterator: ", err) + return +end + +local res, err = it() + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +error: pcre_exec() failed: -8 + + + +=== TEST 31: just not hit match limit +--- http_config + lua_regex_match_limit 5700; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local it, err = ngx.re.gmatch(s, re, "o") +if not it then + ngx.say("failed to gen iterator: ", err) + return +end + +res, err = it() + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +failed to match + diff --git a/t/036-sub.t b/t/036-sub.t index cf65313a53..0e59a92cc3 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -571,3 +571,77 @@ s: a好 --- no_error_log [error] + + +=== TEST 28: just hit match limit +--- http_config + lua_regex_match_limit 5600; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, cnt, err = ngx.re.sub(s, re, "", "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if err then + ngx.say("error: ", err) + return +end +ngx.say("sub: ", cnt) + +--- request + GET /re +--- response_body +error: pcre_exec() failed: -8 + + + +=== TEST 29: just not hit match limit +--- http_config + lua_regex_match_limit 5700; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +local s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, cnt, err = ngx.re.sub(s, re, "", "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if err then + ngx.say("error: ", err) + return +end +ngx.say("sub: ", cnt) + +--- request + GET /re +--- response_body +sub: 0 + diff --git a/t/037-gsub.t b/t/037-gsub.t index 3c5312ba43..ff26fe07d7 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -498,3 +498,78 @@ s: aa --- no_error_log [error] + + +=== TEST 23: just hit match limit +--- http_config + lua_regex_match_limit 5600; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, cnt, err = ngx.re.gsub(s, re, "", "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if err then + ngx.say("error: ", err) + return +end +ngx.say("gsub: ", cnt) + +--- request + GET /re +--- response_body +error: pcre_exec() failed: -8 + + + +=== TEST 24: just not hit match limit +--- http_config + lua_regex_match_limit 5700; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +local s = string.rep([[ABCDEFG]], 10) + +local start = ngx.now() + +local res, cnt, err = ngx.re.gsub(s, re, "", "o") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if err then + ngx.say("error: ", err) + return +end +ngx.say("gsub: ", cnt) + +--- request + GET /re +--- response_body +gsub: 0 +--- timeout: 10 + diff --git a/t/047-match-jit.t b/t/047-match-jit.t index 01b2297126..6c62b96e51 100644 --- a/t/047-match-jit.t +++ b/t/047-match-jit.t @@ -126,3 +126,83 @@ error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] + + +=== TEST 6: just hit match limit +--- http_config + lua_regex_match_limit 2940; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 21) + +local start = ngx.now() + +local res, err = ngx.re.match(s, re, "jo") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +error: pcre_exec() failed: -8 + + + +=== TEST 7: just not hit match limit +--- http_config + lua_regex_match_limit 2950; +--- config + location /re { + content_by_lua_file html/a.lua; + } + +--- user_files +>>> a.lua +local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] + +s = string.rep([[ABCDEFG]], 21) + +local start = ngx.now() + +local res, err = ngx.re.match(s, re, "jo") + +--[[ +ngx.update_time() +local elapsed = ngx.now() - start +ngx.say(elapsed, " sec elapsed.") +]] + +if not res then + if err then + ngx.say("error: ", err) + return + end + ngx.say("failed to match") + return +end + +--- request + GET /re +--- response_body +failed to match + From f36a35d39f70ccdb665b767c86ff5e08d601345d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 16 Jul 2013 21:46:48 -0700 Subject: [PATCH 0152/1981] documented the lua_regex_match_limit directive. --- README | 20 ++++++++++++++++++++ README.markdown | 16 ++++++++++++++++ doc/HttpLuaModule.wiki | 15 +++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/README b/README index 792fecfc5c..81611ed885 100644 --- a/README +++ b/README @@ -299,6 +299,26 @@ Directives the fly* and give rise to infinite variations to avoid hitting the specified limit. + lua_regex_match_limit + syntax: *lua_regex_match_limit * + + default: *lua_regex_match_limit 0* + + context: *http* + + Specifies the "match limit" used by the PCRE library when executing the + ngx.re API. To quote the PCRE manpage, "the limit ... has the effect of + limiting the amount of backtracking that can take place." + + When the limit is hit, the error string "pcre_exec() failed: -8" will be + returned by the ngx.re API functions on the Lua land. + + When setting the limit to 0, the default "match limit" when compiling + the PCRE library is used. And this is the default value of this + directive. + + This directive was first introduced in the "v0.8.5" release. + lua_package_path syntax: *lua_package_path * diff --git a/README.markdown b/README.markdown index 1307d90bc3..646f00f6e6 100644 --- a/README.markdown +++ b/README.markdown @@ -281,6 +281,22 @@ The default number of entries allowed is 1024 and when this limit is reached, ne Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](http://wiki.nginx.org/HttpLuaModule#ngx.re.sub) and [ngx.re.gsub](http://wiki.nginx.org/HttpLuaModule#ngx.re.gsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. +lua_regex_match_limit +--------------------- +**syntax:** *lua_regex_match_limit <num>* + +**default:** *lua_regex_match_limit 0* + +**context:** *http* + +Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](http://wiki.nginx.org/HttpLuaModule#ngx.re.match). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." + +When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](http://wiki.nginx.org/HttpLuaModule#ngx.re.match) functions on the Lua land. + +When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. + +This directive was first introduced in the `v0.8.5` release. + lua_package_path ---------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 986bb87c56..f63011d81c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -268,6 +268,21 @@ The default number of entries allowed is 1024 and when this limit is reached, ne Do not activate the o option for regular expressions (and/or replace string arguments for [[#ngx.re.sub|ngx.re.sub]] and [[#ngx.re.gsub|ngx.re.gsub]]) that are generated ''on the fly'' and give rise to infinite variations to avoid hitting the specified limit. +== lua_regex_match_limit == +'''syntax:''' ''lua_regex_match_limit '' + +'''default:''' ''lua_regex_match_limit 0'' + +'''context:''' ''http'' + +Specifies the "match limit" used by the PCRE library when executing the [[#ngx.re.match|ngx.re API]]. To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." + +When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [[#ngx.re.match|ngx.re API]] functions on the Lua land. + +When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. + +This directive was first introduced in the v0.8.5 release. + == lua_package_path == '''syntax:''' ''lua_package_path '' From 4516e5adf95781fd97c466564ae7ec27137553e1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 17 Jul 2013 12:31:15 -0700 Subject: [PATCH 0153/1981] docs: documented the memory freeing behavior of shdict:flush_all and shdict:flush_expired. --- README | 7 ++++++- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README b/README index 81611ed885..f7c1957d09 100644 --- a/README +++ b/README @@ -4274,7 +4274,9 @@ Nginx API for Lua content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** - Flushes out all the items in the dictionary. + Flushes out all the items in the dictionary. This method does not + actuall free up all the memory blocks in the dictionary but just marks + all the existing items as expired. This feature was first introduced in the "v0.5.0rc17" release. @@ -4292,6 +4294,9 @@ Nginx API for Lua "max_count" argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. + Unlike the flush_all method, this method actually free up the memory + used by the expired items. + This feature was first introduced in the "v0.6.3" release. See also ngx.shared.DICT.flush_all and ngx.shared.DICT. diff --git a/README.markdown b/README.markdown index 646f00f6e6..e603adea7b 100644 --- a/README.markdown +++ b/README.markdown @@ -3910,7 +3910,7 @@ ngx.shared.DICT.flush_all **context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** -Flushes out all the items in the dictionary. +Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. This feature was first introduced in the `v0.5.0rc17` release. @@ -3924,6 +3924,8 @@ ngx.shared.DICT.flush_expired Flushes out the expired items in the dictionary, up to the maximal number specified by the optional `max_count` argument. When the `max_count` argument is given `0` or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. +Unlike the [flush_all](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.flush_all) method, this method actually free up the memory used by the expired items. + This feature was first introduced in the `v0.6.3` release. See also [ngx.shared.DICT.flush_all](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.flush_all) and [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f63011d81c..accb33199a 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3778,7 +3778,7 @@ See also [[#ngx.shared.DICT|ngx.shared.DICT]]. '''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' -Flushes out all the items in the dictionary. +Flushes out all the items in the dictionary. This method does not actuall free up all the memory blocks in the dictionary but just marks all the existing items as expired. This feature was first introduced in the v0.5.0rc17 release. @@ -3791,6 +3791,8 @@ See also [[#ngx.shared.DICT.flush_expired|ngx.shared.DICT.flush_expired]] and [[ Flushes out the expired items in the dictionary, up to the maximal number specified by the optional max_count argument. When the max_count argument is given 0 or not given at all, then it means unlimited. Returns the number of items that have actually been flushed. +Unlike the [[#ngx.shared.DICT.flush_all|flush_all]] method, this method actually free up the memory used by the expired items. + This feature was first introduced in the v0.6.3 release. See also [[#ngx.shared.DICT.flush_all|ngx.shared.DICT.flush_all]] and [[#ngx.shared.DICT|ngx.shared.DICT]]. From 0d8143091437cdeeaf4c77309a3da07f350a59e1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 18 Jul 2013 12:53:33 -0700 Subject: [PATCH 0154/1981] bumped version to 0.8.5. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index f7c1957d09..922c918775 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.4 - () released on 10 + This document describes ngx_lua v0.8.5 + () released on 18 July 2013. Synopsis diff --git a/README.markdown b/README.markdown index e603adea7b..b951914f8a 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 July 2013. +This document describes ngx_lua [v0.8.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 18 July 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index accb33199a..a19757c41e 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.4] released on 10 July 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.5] released on 18 July 2013. = Synopsis = From eecb52bc480c7a06834ccde97d65202b7d68fc4c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 22 Jul 2013 18:21:57 -0700 Subject: [PATCH 0155/1981] bugfix: when our atpanic handler for Lua VM gets called, the Lua VM is not recoverable for future use. so now we try to quit the current nginx worker gracefully so that the nginx master can spawn a new one. --- src/ngx_http_lua_exception.c | 1 + src/ngx_http_lua_util.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ngx_http_lua_exception.c b/src/ngx_http_lua_exception.c index c1adc0a551..92ed57a8f2 100644 --- a/src/ngx_http_lua_exception.c +++ b/src/ngx_http_lua_exception.c @@ -43,6 +43,7 @@ ngx_http_lua_atpanic(lua_State *L) } ngx_log_stderr(0, "lua atpanic: Lua VM crashed, reason: %*s", len, s); + ngx_quit = 1; /* restore nginx execution */ NGX_LUA_EXCEPTION_THROW(1); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index f4bd59661c..e1c50b9ffa 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1301,6 +1301,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, case LUA_ERRMEM: err = "memory allocation error"; + ngx_quit = 1; break; case LUA_ERRERR: From 60902726d4a7164a70aec9db05d0cc68686f32ad Mon Sep 17 00:00:00 2001 From: cubicdaiya Date: Tue, 23 Jul 2013 22:41:29 +0900 Subject: [PATCH 0156/1981] give the argument of 'void' to function definitions which has no arguments A function definition which has no arguments is traditional-style and deprecated --- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 2b07e52545..d5064fe1da 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -359,7 +359,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t -ngx_http_lua_body_filter_init() +ngx_http_lua_body_filter_init(void) { dd("calling body filter init"); ngx_http_next_body_filter = ngx_http_top_body_filter; diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index cb335b89db..a459cf9ad9 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -302,7 +302,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) ngx_int_t -ngx_http_lua_header_filter_init() +ngx_http_lua_header_filter_init(void) { dd("calling header filter init"); ngx_http_next_header_filter = ngx_http_top_header_filter; From 918f9a2391a86566920e480e6721b11dda3f45de Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 19:31:16 -0700 Subject: [PATCH 0157/1981] refactor: removed the unused C function ngx_http_lua_clfactory_loadstring. --- src/ngx_http_lua_clfactory.c | 7 ------- src/ngx_http_lua_clfactory.h | 1 - 2 files changed, 8 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 0cc26aac69..79aa1ba3f3 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -649,13 +649,6 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) } -int -ngx_http_lua_clfactory_loadstring(lua_State *L, const char *s) -{ - return ngx_http_lua_clfactory_loadbuffer(L, s, strlen(s), s); -} - - int ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, size_t size, const char *name) diff --git a/src/ngx_http_lua_clfactory.h b/src/ngx_http_lua_clfactory.h index 6029df7174..beecb3d5ea 100644 --- a/src/ngx_http_lua_clfactory.h +++ b/src/ngx_http_lua_clfactory.h @@ -20,7 +20,6 @@ int ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename); -int ngx_http_lua_clfactory_loadstring(lua_State *L, const char *s); int ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, size_t size, const char *name); From 1db1e71f18730721314199e174c5ec3d066b7a7a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 22:01:12 -0700 Subject: [PATCH 0158/1981] refactor: removed the useless code for reading Lua code from stdin. --- src/ngx_http_lua_clfactory.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 79aa1ba3f3..9ba529c900 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -504,9 +504,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, error: - if (lf->f != stdin) { - fclose(lf->f); /* close file (even in case of errors) */ - } + fclose(lf->f); /* close file (even in case of errors) */ filename = lua_tostring(L, fname_index) + 1; @@ -544,17 +542,11 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.end_code.ptr = CLFACTORY_END_CODE; lf.end_code_len = CLFACTORY_END_SIZE; - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - - } else { - lua_pushfstring(L, "@%s", filename); - lf.f = fopen(filename, "r"); + lua_pushfstring(L, "@%s", filename); - if (lf.f == NULL) { - return clfactory_errfile(L, "open", fname_index); - } + lf.f = fopen(filename, "r"); + if (lf.f == NULL) { + return clfactory_errfile(L, "open", fname_index); } c = getc(lf.f); From fb38e4b277c45d0e595e78775197ee45f0a0eaab Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 22:13:41 -0700 Subject: [PATCH 0159/1981] various coding style fixes in the closure factory. --- src/ngx_http_lua_clfactory.c | 53 ++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 9ba529c900..decb7ea6b4 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -247,11 +247,12 @@ typedef enum { NGX_LUA_TEXT_FILE, NGX_LUA_BT_LUA, NGX_LUA_BT_LJ -} clfactory_file_type_e; +} ngx_http_lua_clfactory_file_type_e; typedef struct { - clfactory_file_type_e file_type; + ngx_http_lua_clfactory_file_type_e file_type; + int sent_begin; int sent_end; int extraline; @@ -268,7 +269,7 @@ typedef struct { char str[MAX_END_CODE_SIZE]; } end_code; char buff[LUAL_BUFFERSIZE]; -} clfactory_file_ctx_t; +} ngx_http_lua_clfactory_file_ctx_t; typedef struct { @@ -276,17 +277,20 @@ typedef struct { int sent_end; const char *s; size_t size; -} clfactory_buffer_ctx_t; +} ngx_http_lua_clfactory_buffer_ctx_t; -static const char *clfactory_getF(lua_State *L, void *ud, size_t *size); -static int clfactory_errfile(lua_State *L, const char *what, int fname_index); -static const char *clfactory_getS(lua_State *L, void *ud, size_t *size); +static const char *ngx_http_lua_clfactory_getF(lua_State *L, void *ud, + size_t *size); +static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, + int fname_index); +static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, + size_t *size); int -ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, - int fname_index) +ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, + ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index) { int x = 1, size_of_int, size_of_size_t, little_endian, size_of_inst, version, stripped; @@ -526,7 +530,8 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) { int c, status, readstatus; ngx_flag_t sharp; - clfactory_file_ctx_t lf; + + ngx_http_lua_clfactory_file_ctx_t lf; /* index of filename on the stack */ int fname_index; @@ -546,7 +551,7 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.f = fopen(filename, "r"); if (lf.f == NULL) { - return clfactory_errfile(L, "open", fname_index); + return ngx_http_lua_clfactory_errfile(L, "open", fname_index); } c = getc(lf.f); @@ -569,7 +574,7 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) { - return clfactory_errfile(L, "reopen", fname_index); + return ngx_http_lua_clfactory_errfile(L, "reopen", fname_index); } /* check whether lib jit exists */ @@ -622,7 +627,8 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) } lf.sent_begin = lf.sent_end = 0; - status = lua_load(L, clfactory_getF, &lf, lua_tostring(L, -1)); + status = lua_load(L, ngx_http_lua_clfactory_getF, &lf, + lua_tostring(L, -1)); readstatus = ferror(lf.f); @@ -632,7 +638,7 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) if (readstatus) { lua_settop(L, fname_index); /* ignore results from `lua_load' */ - return clfactory_errfile(L, "read", fname_index); + return ngx_http_lua_clfactory_errfile(L, "read", fname_index); } lua_remove(L, fname_index); @@ -643,27 +649,28 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) int ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, - size_t size, const char *name) + size_t size, const char *name) { - clfactory_buffer_ctx_t ls; + ngx_http_lua_clfactory_buffer_ctx_t ls; ls.s = buff; ls.size = size; ls.sent_begin = 0; ls.sent_end = 0; - return lua_load(L, clfactory_getS, &ls, name); + return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name); } static const char * -clfactory_getF(lua_State *L, void *ud, size_t *size) +ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size) { char *buf; size_t num; - clfactory_file_ctx_t *lf; - lf = (clfactory_file_ctx_t *) ud; + ngx_http_lua_clfactory_file_ctx_t *lf; + + lf = (ngx_http_lua_clfactory_file_ctx_t *) ud; if (lf->extraline) { lf->extraline = 0; @@ -728,7 +735,7 @@ clfactory_getF(lua_State *L, void *ud, size_t *size) static int -clfactory_errfile(lua_State *L, const char *what, int fname_index) +ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index) { const char *serr; const char *filename; @@ -750,9 +757,9 @@ clfactory_errfile(lua_State *L, const char *what, int fname_index) static const char * -clfactory_getS(lua_State *L, void *ud, size_t *size) +ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) { - clfactory_buffer_ctx_t *ls = ud; + ngx_http_lua_clfactory_buffer_ctx_t *ls = ud; if (ls->sent_begin == 0) { ls->sent_begin = 1; From d1c654b3ef1a665416a87cbb18106c8f88f72543 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 22:55:15 -0700 Subject: [PATCH 0160/1981] bugfix: the error message was misleading when the *_by_lua_file directives failed to load the Lua file specified. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_directive.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_logby.c | 2 +- src/ngx_http_lua_rewriteby.c | 2 +- t/001-set.t | 18 ++++++++++++++++++ t/002-content.t | 20 +++++++++++++++++++- t/023-rewrite/sanity.t | 20 +++++++++++++++++++- t/024-access/sanity.t | 20 +++++++++++++++++++- t/041-header-filter.t | 20 +++++++++++++++++++- t/075-logby.t | 19 +++++++++++++++++++ t/081-bytecode.t | 2 +- t/082-body-filter.t | 20 +++++++++++++++++++- 15 files changed, 140 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 68cc777ef3..83f4255c3e 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -214,7 +214,7 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load lua inlined code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index d5064fe1da..7c78e7d572 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -234,7 +234,7 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 28364617db..e8afcdef22 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -260,7 +260,7 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 746ded665e..4de78a89b2 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -368,7 +368,7 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua file: %s", err); + "failed to load external Lua file: %s", err); return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index a459cf9ad9..4106966ec3 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -221,7 +221,7 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 3038b255b3..b9fb758a21 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -197,7 +197,7 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua file code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 2f58b6c791..4801b5144d 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -216,7 +216,7 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua file code: %s", err); + "failed to load external Lua file: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/t/001-set.t b/t/001-set.t index 8bb83570d6..5f20f2396b 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -779,3 +779,21 @@ in function 'error' in function 'bar' in function 'foo' + + +=== TEST 46: Lua file does not exist +--- config + location /lua { + set_by_lua_file $a 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/ + diff --git a/t/002-content.t b/t/002-content.t index 89b42fccea..82112cca28 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 15); +plan tests => repeat_each() * (blocks() * 2 + 16); #no_diff(); #no_long_string(); @@ -784,3 +784,21 @@ world --- response_body 10051532 + + +=== TEST 40: Lua file does not exist +--- config + location /lua { + content_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/ + diff --git a/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t index 81fcd0f66c..39f473f043 100644 --- a/t/023-rewrite/sanity.t +++ b/t/023-rewrite/sanity.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 8); #no_diff(); #no_long_string(); @@ -736,3 +736,21 @@ abc --- 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/ + diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 504d56f818..856d5b4156 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 7); +plan tests => repeat_each() * (blocks() * 2 + 8); #no_diff(); no_long_string(); @@ -680,3 +680,21 @@ GET / --- response_headers X-Foo: bar + + +=== TEST 36: Lua file does not exist +--- config + location /lua { + access_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/ + diff --git a/t/041-header-filter.t b/t/041-header-filter.t index f0276307d4..99f8deeb74 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -11,7 +11,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 91; +plan tests => repeat_each() * 92; #no_diff(); #no_long_string(); @@ -763,3 +763,21 @@ in function 'error' in function 'bar' in function 'foo' + + +=== TEST 41: Lua file does not exist +--- config + location /lua { + echo ok; + header_filter_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 +--- ignore_response +--- error_log eval +qr/failed to load external Lua file: cannot open .*? No such file or directory/ + diff --git a/t/075-logby.t b/t/075-logby.t index 91a90efa14..b7ba08835f 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -518,3 +518,22 @@ in function 'error' in function 'bar' in function 'foo' + + +=== TEST 29: Lua file does not exist +--- config + location /lua { + echo ok; + log_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 +ok +--- error_log eval +qr/failed to load external Lua file: cannot open .*? No such file or directory/ + diff --git a/t/081-bytecode.t b/t/081-bytecode.t index 3fd1fb544b..6a3db5153e 100644 --- a/t/081-bytecode.t +++ b/t/081-bytecode.t @@ -82,7 +82,7 @@ hello --- response_body error --- error_log -failed to load Lua inlined code: bad byte-code header in +failed to load external Lua file: bad byte-code header in diff --git a/t/082-body-filter.t b/t/082-body-filter.t index e6fc6212b2..7892c66d3f 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -11,7 +11,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 6); +plan tests => repeat_each() * (blocks() * 3 + 4); #no_diff(); #no_long_string(); @@ -507,3 +507,21 @@ hello worldhello world --- no_error_log [error] + + +=== TEST 19: Lua file does not exist +--- config + location /lua { + echo ok; + body_filter_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 +--- ignore_response +--- error_log eval +qr/failed to load external Lua file: cannot open .*? No such file or directory/ + From 197332049e830b25734447dae29088c58f0a16f6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 23:02:22 -0700 Subject: [PATCH 0161/1981] added a (passing) test for using .lua files with a shebang line in the content_by_lua_file directive. --- t/002-content.t | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/t/002-content.t b/t/002-content.t index 82112cca28..b273492fe9 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 16); +plan tests => repeat_each() * (blocks() * 2 + 17); #no_diff(); #no_long_string(); @@ -802,3 +802,22 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file: cannot open .*? No such file or directory/ + + +=== TEST 41: .lua file with shebang +--- config + location /lua { + content_by_lua_file html/test.lua; + } +--- user_files +>>> test.lua +#!/bin/lua + +ngx.say("line ", debug.getinfo(1).currentline) +--- request +GET /lua?a=1&b=2 +--- response_body +line 3 +--- no_error_log +[error] + From 6859f6f8ba5690dfad50e58a869197addca4acea Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 27 Jul 2013 23:08:45 -0700 Subject: [PATCH 0162/1981] minor error message fixes in the Lua code cache. --- src/ngx_http_lua_cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 726d280e34..489328259b 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -155,7 +155,7 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, *err = (char *) lua_tostring(L, -1); } else { - *err = "syntax error"; + *err = "unknown error"; } } @@ -226,7 +226,7 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, *err = (char *) lua_tostring(L, -1); } else { - *err = "syntax error"; + *err = "unknown error"; } } From 00c5fb411852a1a31c185b225925a705c259c0d1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 13:03:07 -0700 Subject: [PATCH 0163/1981] one minor coding style fix. --- src/ngx_http_lua_timer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 5b6839a571..23c3614463 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -467,6 +467,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) } else if (rc == NGX_DONE) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); + } else { rc = NGX_OK; } From ffe89f22642e2d1b39f96ea4a74b7d04fffb32cd Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 13:11:11 -0700 Subject: [PATCH 0164/1981] refactor: abstracted the ngx.ctx releasing logic to eliminate code duplication. --- src/ngx_http_lua_logby.c | 12 +----------- src/ngx_http_lua_util.c | 25 ++++++++++++++++--------- src/ngx_http_lua_util.h | 3 +++ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index b9fb758a21..4c36654f93 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -104,19 +104,9 @@ ngx_http_lua_log_handler(ngx_http_request_t *r) * before log phase handlers */ if (ctx->ctx_ref != LUA_NOREF) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua release ngx.ctx"); - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - L = lmcf->lua; - - lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); - lua_rawget(L, LUA_REGISTRYINDEX); - - luaL_unref(L, -1, ctx->ctx_ref); - ctx->ctx_ref = LUA_NOREF; - lua_pop(L, 1); + ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); } return rc; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index e1c50b9ffa..b6f290ec07 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -956,16 +956,8 @@ ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) if (ctx->ctx_ref != LUA_NOREF) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (forcible || llcf->log_handler == NULL) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua release ngx.ctx at ref %d", ctx->ctx_ref); - - lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); - lua_rawget(L, LUA_REGISTRYINDEX); - luaL_unref(L, -1, ctx->ctx_ref); - ctx->ctx_ref = LUA_NOREF; - lua_pop(L, 1); + ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); } } @@ -974,6 +966,21 @@ ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) } +void +ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, + ngx_http_lua_ctx_t *ctx) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "lua release ngx.ctx at ref %d", ctx->ctx_ref); + + lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, ctx->ctx_ref); + ctx->ctx_ref = LUA_NOREF; + lua_pop(L, 1); +} + + /* * description: * run a Lua coroutine specified by ctx->cur_co_ctx->co diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index b7f7ad27f9..16fd76c767 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -168,6 +168,9 @@ void ngx_http_lua_finalize_fake_request(ngx_http_request_t *r, void ngx_http_lua_close_fake_connection(ngx_connection_t *c); +void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, + ngx_http_lua_ctx_t *ctx); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ From e24ffb7518e7560df9673f513f11a5a66fadcdb1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 13:26:43 -0700 Subject: [PATCH 0165/1981] bugfix: use of the ngx.ctx table in the context of ngx.timer callbacks would leak memory. --- src/ngx_http_lua_util.c | 5 ++++- t/106-timer.t | 45 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index b6f290ec07..5b9e7c5983 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -956,7 +956,10 @@ ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) if (ctx->ctx_ref != LUA_NOREF) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (forcible || llcf->log_handler == NULL) { + if (forcible + || r->connection->fd == -1 /* being a fake request */ + || llcf->log_handler == NULL) + { ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); } } diff --git a/t/106-timer.t b/t/106-timer.t index 7e5f0b22b4..753c167318 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -13,7 +13,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 8 + 73); +plan tests => repeat_each() * (blocks() * 8 + 76); #no_diff(); no_long_string(); @@ -2119,3 +2119,46 @@ qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, c "timer user args: 1 hello true", ] + + +=== TEST 31: use of ngx.ctx +--- config + location /t { + content_by_lua ' + local begin = ngx.now() + local function f(premature) + ngx.ctx.s = "hello" + print("elapsed: ", ngx.now() - begin) + print("timer prematurely expired: ", premature) + end + local ok, err = ngx.timer.at(0, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + '; + log_by_lua return; + } +--- request +GET /t + +--- response_body +registered timer + +--- wait: 0.1 +--- no_error_log +[error] +[alert] +[crit] +timer prematurely expired: true + +--- error_log eval +[ +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\d*, context: ngx\.timer/, +"lua ngx.timer expired", +"http lua close fake http connection", +"timer prematurely expired: false", +"lua release ngx.ctx at ref ", +] + From 32aadb76d9dfcdf672bb5d9ff6983363d3c041ed Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 18:05:27 -0700 Subject: [PATCH 0166/1981] fixed a test case. --- t/106-timer.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/106-timer.t b/t/106-timer.t index 753c167318..986fec21d2 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -2155,7 +2155,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\d*, context: ngx\.timer/, +qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: .*?, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", From 629330431d96d2d2f1688984d7c8621f06f5d5a2 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 18:10:36 -0700 Subject: [PATCH 0167/1981] bugfix: memory leak would happen when using ngx.ctx before another nginx module (other than ngx_lua) initiates an internal redirect. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_common.h | 1 + src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_setby.c | 2 +- src/ngx_http_lua_subrequest.c | 12 ++--- src/ngx_http_lua_timer.c | 2 +- src/ngx_http_lua_util.c | 55 +++++++++++++++-------- src/ngx_http_lua_util.h | 16 ++++--- t/033-ctx.t | 74 ++++++++++++++++++++++++++++++- 12 files changed, 133 insertions(+), 39 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 83f4255c3e..a2665c73cf 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -286,7 +286,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } /* }}} */ diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 7c78e7d572..dd93a05080 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -307,7 +307,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 25cd9a42d5..85a2ad48ae 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -288,6 +288,7 @@ struct ngx_http_lua_co_ctx_s { typedef struct ngx_http_lua_ctx_s { + ngx_http_request_t *request; ngx_http_handler_pt resume_handler; ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index e8afcdef22..83baaf8070 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -81,7 +81,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } /* }}} */ diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 4106966ec3..8bb225b583 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -280,7 +280,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 4801b5144d..5634313fea 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -284,7 +284,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } /* }}} */ diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 75faad6af5..2627cff323 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -72,7 +72,7 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; } diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 93e488fdcd..0c2a71e4bc 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -541,12 +541,6 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) * sr_ctx->body = NULL */ - ngx_http_lua_init_ctx(sr_ctx); - - sr_ctx->capture = 1; - sr_ctx->index = index; - sr_ctx->last_body = &sr_ctx->body; - psr_data->ctx = sr_ctx; psr_data->pr_co_ctx = coctx; @@ -559,6 +553,12 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } + ngx_http_lua_init_ctx(sr, sr_ctx); + + sr_ctx->capture = 1; + sr_ctx->index = index; + sr_ctx->last_body = &sr_ctx->body; + ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, body, vars_action, diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 23c3614463..079a90ffff 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -429,7 +429,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) } cln->handler = ngx_http_lua_request_cleanup_handler; - cln->data = r; + cln->data = ctx; ctx->cleanup = &cln->handler; ctx->entered_content_phase = 1; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 5b9e7c5983..1b9d24c60a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -911,23 +911,26 @@ ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r) void ngx_http_lua_request_cleanup_handler(void *data) { - ngx_http_lua_request_cleanup(data, 0 /* forcible */); + ngx_http_lua_ctx_t *ctx = data; + + ngx_http_lua_request_cleanup(ctx, 0 /* forcible */); } void -ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) +ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) { lua_State *L; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_loc_conf_t *llcf; + ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_ctx_t *cur_ctx; + + r = ctx->request; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua request cleanup: forcible=%d", forcible); - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - /* force coroutine handling the request quit */ if (ctx == NULL) { dd("ctx is NULL"); @@ -955,12 +958,26 @@ ngx_http_lua_request_cleanup(ngx_http_request_t *r, int forcible) if (ctx->ctx_ref != LUA_NOREF) { - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (forcible - || r->connection->fd == -1 /* being a fake request */ - || llcf->log_handler == NULL) - { + if (forcible || r->connection->fd == -1 /* being a fake request */) { ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); + + } else { + + cur_ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + if (cur_ctx != ctx) { + /* internal redirects happened */ + ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); + + } else { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_handler == NULL) { + /* no log_by_lua* configured */ + ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, + ctx); + } + } } } @@ -1406,7 +1423,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r, 0); + ngx_http_lua_request_cleanup(ctx, 0); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1464,7 +1481,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r, 0); + ngx_http_lua_request_cleanup(ctx, 0); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " "user coroutine has no parent"); @@ -2062,7 +2079,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r, 1 /* forcible */); + ngx_http_lua_request_cleanup(ctx, 1 /* forcible */); if (ctx->exec_uri.data[0] == '@') { if (ctx->exec_args.len > 0) { @@ -2167,7 +2184,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r, 0); + ngx_http_lua_request_cleanup(ctx, 0); if (ctx->buffering && r->headers_out.status) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); @@ -2483,8 +2500,8 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } - ngx_http_lua_request_cleanup(r, 1 /* forcible */); - ngx_http_lua_init_ctx(ctx); + ngx_http_lua_request_cleanup(ctx, 1 /* forcible */); + ngx_http_lua_init_ctx(r, ctx); return NGX_OK; } @@ -3221,7 +3238,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if (ctx->on_abort_co_ctx == NULL) { r->connection->error = 1; - ngx_http_lua_request_cleanup(r, 0); + ngx_http_lua_request_cleanup(ctx, 0); ngx_http_lua_finalize_request(r, rc); return; } @@ -3234,7 +3251,7 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { - ngx_http_lua_request_cleanup(r, 0); + ngx_http_lua_request_cleanup(ctx, 0); ngx_http_lua_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 16fd76c767..a5648c652b 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -104,7 +104,7 @@ void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, void ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r); -void ngx_http_lua_request_cleanup(ngx_http_request_t *r, int foricible); +void ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int foricible); void ngx_http_lua_request_cleanup_handler(void *data); @@ -178,11 +178,15 @@ void ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, } -#define ngx_http_lua_init_ctx(ctx) \ - ngx_memzero(ctx, sizeof(ngx_http_lua_ctx_t)); \ - ctx->ctx_ref = LUA_NOREF; \ - ctx->entry_co_ctx.co_ref = LUA_NOREF; \ +static ngx_inline void +ngx_http_lua_init_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_memzero(ctx, sizeof(ngx_http_lua_ctx_t)); + ctx->ctx_ref = LUA_NOREF; + ctx->entry_co_ctx.co_ref = LUA_NOREF; ctx->resume_handler = ngx_http_lua_wev_handler; + ctx->request = r; +} static ngx_inline ngx_http_lua_ctx_t * @@ -195,7 +199,7 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) return NULL; } - ngx_http_lua_init_ctx(ctx); + ngx_http_lua_init_ctx(r, ctx); ngx_http_set_ctx(r, ctx, ngx_http_lua_module); return ctx; diff --git a/t/033-ctx.t b/t/033-ctx.t index 472fccc320..04f0a8d9ec 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 4); +plan tests => repeat_each() * (blocks() * 3 + 6); #no_diff(); #no_long_string(); @@ -318,3 +318,75 @@ ctx.foo = 32 --- no_error_log [error] + + +=== TEST 14: set ngx.ctx before internal redirects performed by other nginx modules +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = "hello world"; + '; + echo_exec /foo; + } + + location = /foo { + echo hello; + } +--- request +GET /t +--- response_body +hello +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua release ngx.ctx at ref + + + +=== TEST 15: set ngx.ctx before internal redirects performed by other nginx modules (with log_by_lua) +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = "hello world"; + '; + echo_exec /foo; + } + + location = /foo { + echo hello; + log_by_lua return; + } +--- request +GET /t +--- response_body +hello +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua release ngx.ctx at ref + + + +=== TEST 16: set ngx.ctx before simple uri rewrite performed by other nginx modules +--- config + location = /t { + set_by_lua $a 'ngx.ctx.foo = "hello world"; return 1'; + rewrite ^ /foo last; + echo blah; + } + + location = /foo { + echo foo; + } +--- request +GET /t +--- response_body +foo +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua release ngx.ctx at ref + From 0aa9332f59d498c19c770d5a8ebb12cd533b07b3 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 19:23:12 -0700 Subject: [PATCH 0168/1981] bugfix: we incorrectly returned 500 in our output header filter, body filter, and log-phase handlers upon errors. bugfix: Lua stack overflow might happen when we failed to load Lua code from the code cache. --- src/ngx_http_lua_accessby.c | 10 +--------- src/ngx_http_lua_bodyfilterby.c | 12 ++---------- src/ngx_http_lua_cache.c | 29 ++++++++++++++++++++--------- src/ngx_http_lua_cache.h | 2 +- src/ngx_http_lua_contentby.c | 10 +--------- src/ngx_http_lua_directive.c | 10 +--------- src/ngx_http_lua_headerfilterby.c | 12 ++---------- src/ngx_http_lua_logby.c | 12 ++---------- src/ngx_http_lua_rewriteby.c | 10 +--------- 9 files changed, 31 insertions(+), 76 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index a2665c73cf..244dde45ba 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -179,7 +179,6 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) ngx_int_t ngx_http_lua_access_handler_file(ngx_http_request_t *r) { - char *err; u_char *script_path; ngx_int_t rc; ngx_str_t eval_src; @@ -206,16 +205,9 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->access_src_key, - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index dd93a05080..b15a3ccaed 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -201,7 +201,6 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; ngx_str_t eval_src; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -225,18 +224,11 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, - llcf->body_filter_src_key, &err, + llcf->body_filter_src_key, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } /* make sure we have a valid code chunk */ diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 489328259b..f814fcad45 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -177,11 +177,15 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, ngx_int_t ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, - const u_char *cache_key, char **err, unsigned enabled) + const u_char *cache_key, unsigned enabled) { int rc; u_char *p; u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1]; + int n; + const char *err = NULL; + + n = lua_gettop(L); /* calculate digest of script file path */ dd("code cache enabled: %d", (int) enabled); @@ -219,18 +223,18 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, if (rc != 0) { /* Oops! error occured when loading Lua script */ if (rc == LUA_ERRMEM) { - *err = "memory allocation error"; + err = "memory allocation error"; } else { if (lua_isstring(L, -1)) { - *err = (char *) lua_tostring(L, -1); + err = lua_tostring(L, -1); } else { - *err = "unknown error"; + err = "unknown error"; } } - return NGX_ERROR; + goto error; } if (enabled) { @@ -239,22 +243,29 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, rc = ngx_http_lua_cache_store_code(L, (char *) cache_key); if (rc != NGX_OK) { - *err = "fail to generate new closure from the closure factory"; - return NGX_ERROR; + err = "fail to generate new closure from the closure factory"; + goto error; } } else { /* call closure factory to generate new closure */ rc = lua_pcall(L, 0, 1, 0); if (rc != 0) { - dd("Error: failed to call closure factory!!"); - return NGX_ERROR; + err = "failed to call closure factory"; + goto error; } ngx_http_lua_clear_package_loaded(L); } return NGX_OK; + +error: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "failed to load external Lua file: %s", err); + + lua_settop(L, n); + return NGX_ERROR; } diff --git a/src/ngx_http_lua_cache.h b/src/ngx_http_lua_cache.h index f8c13e903d..a80c7c59b3 100644 --- a/src/ngx_http_lua_cache.h +++ b/src/ngx_http_lua_cache.h @@ -16,7 +16,7 @@ ngx_int_t ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, const u_char *cache_key, const char *name, char **err, unsigned enabled); ngx_int_t ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, - const u_char *cache_key, char **err, unsigned enabled); + const u_char *cache_key, unsigned enabled); #endif /* _NGX_HTTP_LUA_CACHE_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 83baaf8070..38260b24d5 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -231,7 +231,6 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; ngx_str_t eval_src; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -252,16 +251,9 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->content_src_key, - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 4de78a89b2..e13e7bdbfb 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -329,7 +329,6 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; size_t nargs; ngx_http_lua_set_var_data_t *filter_data = data; @@ -360,16 +359,9 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, filter_data->key, - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 8bb225b583..4b44390e4e 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -188,7 +188,6 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; ngx_str_t eval_src; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -212,18 +211,11 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, - llcf->header_filter_src_key, &err, + llcf->header_filter_src_key, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } /* make sure we have a valid code chunk */ diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 4c36654f93..5998fffc67 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -158,7 +158,6 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; ngx_str_t eval_src; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -179,17 +178,10 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->log_src_key, - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } return ngx_http_lua_log_by_chunk(L, r); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 5634313fea..d33dbfe794 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -187,7 +187,6 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) u_char *script_path; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; ngx_str_t eval_src; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -208,16 +207,9 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) /* load Lua script file (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->rewrite_src_key, - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load external Lua file: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } From c6426fb5ed4e9b9ad5380b0d42f8882cc3c0b8d4 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 29 Jul 2013 19:32:51 -0700 Subject: [PATCH 0169/1981] fixed the test plan in t/033-ctx.t. --- t/033-ctx.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/033-ctx.t b/t/033-ctx.t index 04f0a8d9ec..78614a526a 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 6); +plan tests => repeat_each() * (blocks() * 3 + 7); #no_diff(); #no_long_string(); From 5edc4b3fc0311a0745272924af0ad6cac802b560 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 30 Jul 2013 12:50:34 -0700 Subject: [PATCH 0170/1981] one minor coding style fix. thanks Guanlan Dai. --- src/ngx_http_lua_headers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index fb7f557780..925132b6cc 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -286,7 +286,8 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) static int -ngx_http_lua_ngx_req_get_headers(lua_State *L) { +ngx_http_lua_ngx_req_get_headers(lua_State *L) +{ ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_request_t *r; From e4641a3c77c04458954378d22f2bc84221c4bd5b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 30 Jul 2013 12:54:23 -0700 Subject: [PATCH 0171/1981] more coding style fixes. --- src/ngx_http_lua_directive.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index e13e7bdbfb..8cdb02f209 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -277,7 +277,7 @@ ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, - ngx_http_variable_value_t *v, void *data) + ngx_http_variable_value_t *v, void *data) { lua_State *L; ngx_int_t rc; @@ -322,7 +322,7 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, - ngx_http_variable_value_t *v, void *data) + ngx_http_variable_value_t *v, void *data) { lua_State *L; ngx_int_t rc; @@ -715,7 +715,7 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) char * ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) + void *conf) { u_char *p; ngx_str_t *value; @@ -796,7 +796,7 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, char * ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) + void *conf) { u_char *p; ngx_str_t *value; @@ -878,7 +878,7 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, char * ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) + void *conf) { u_char *name; ngx_str_t *value; From abaa7f4272563ff132a59c54128feebe52299c1f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 30 Jul 2013 13:06:15 -0700 Subject: [PATCH 0172/1981] more coding style fixes. --- src/ngx_http_lua_api.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 6 +++--- src/ngx_http_lua_cache.c | 2 +- src/ngx_http_lua_ctx.c | 2 +- src/ngx_http_lua_regex.c | 2 +- src/ngx_http_lua_string.c | 3 +-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index 9597fee468..fcf07ac08d 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -31,7 +31,7 @@ ngx_http_lua_get_request(lua_State *L) ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, - lua_CFunction func) + lua_CFunction func) { lua_State *L; ngx_http_lua_main_conf_t *lmcf; diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index b15a3ccaed..12894e01e4 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -50,7 +50,7 @@ static char ngx_http_lua_body_filter_chain_key; * */ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, - ngx_chain_t *in) + ngx_chain_t *in) { /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); @@ -85,7 +85,7 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_int_t ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r, - ngx_chain_t *in) + ngx_chain_t *in) { ngx_int_t rc; u_char *err_msg; @@ -451,7 +451,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L) int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx) + ngx_http_lua_ctx_t *ctx) { int type; int idx; diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index f814fcad45..41a4626e5d 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -177,7 +177,7 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, ngx_int_t ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, - const u_char *cache_key, unsigned enabled) + const u_char *cache_key, unsigned enabled) { int rc; u_char *p; diff --git a/src/ngx_http_lua_ctx.c b/src/ngx_http_lua_ctx.c index 7ca1353334..1bca45b251 100644 --- a/src/ngx_http_lua_ctx.c +++ b/src/ngx_http_lua_ctx.c @@ -76,7 +76,7 @@ ngx_http_lua_ngx_set_ctx(lua_State *L) int ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int index) + ngx_http_lua_ctx_t *ctx, int index) { if (index < 0) { index = lua_gettop(L) + index + 1; diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index b32c2f281f..593fae8ea9 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1080,7 +1080,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) static ngx_uint_t ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_http_lua_regex_compile_t *re, - ngx_str_t *opts, int narg) + ngx_str_t *opts, int narg) { u_char *p; const char *msg; diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 2b2d68a3bb..9d501eee0f 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -212,8 +212,7 @@ ngx_http_lua_ngx_quote_sql_str(lua_State *L) static uintptr_t -ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, - size_t size) +ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) { ngx_uint_t n; From c7a52824a49d30e5462cf39f1f7f53d72988a95b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 30 Jul 2013 13:18:10 -0700 Subject: [PATCH 0173/1981] more coding style fixes. --- src/ngx_http_lua_args.c | 6 ++++-- src/ngx_http_lua_string.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index 9be9ff3288..b21dd15232 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -21,7 +21,8 @@ static int ngx_http_lua_ngx_req_get_post_args(lua_State *L); static int -ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { +ngx_http_lua_ngx_req_set_uri_args(lua_State *L) +{ ngx_http_request_t *r; ngx_str_t args; const char *msg; @@ -80,7 +81,8 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { static int -ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { +ngx_http_lua_ngx_req_get_uri_args(lua_State *L) +{ ngx_http_request_t *r; u_char *buf; u_char *last; diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 9d501eee0f..2a7ec72592 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -491,7 +491,8 @@ ngx_http_lua_ngx_crc32_long(lua_State *L) static int -ngx_http_lua_ngx_encode_args(lua_State *L) { +ngx_http_lua_ngx_encode_args(lua_State *L) +{ ngx_str_t args; if (lua_gettop(L) != 1) { @@ -507,7 +508,8 @@ ngx_http_lua_ngx_encode_args(lua_State *L) { static int -ngx_http_lua_ngx_decode_args(lua_State *L) { +ngx_http_lua_ngx_decode_args(lua_State *L) +{ u_char *buf; u_char *tmp; size_t len = 0; From 52f48e0761ad54642b4f2b7e67c9c9e46b3d34b3 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 30 Jul 2013 17:58:11 -0700 Subject: [PATCH 0174/1981] bugfix: we incorrectly returned 500 in our output header filter, body filter, and log-phase handlers upon inlined Lua code loading errors. bugfix: Lua stack overflow might happen when we failed to load inlined Lua code from the code cache. --- src/ngx_http_lua_accessby.c | 10 +--------- src/ngx_http_lua_bodyfilterby.c | 12 ++---------- src/ngx_http_lua_cache.c | 28 ++++++++++++++++++---------- src/ngx_http_lua_cache.h | 2 +- src/ngx_http_lua_contentby.c | 10 +--------- src/ngx_http_lua_directive.c | 10 +--------- src/ngx_http_lua_headerfilterby.c | 12 ++---------- src/ngx_http_lua_logby.c | 12 ++---------- src/ngx_http_lua_rewriteby.c | 10 +--------- 9 files changed, 29 insertions(+), 77 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 244dde45ba..0cebc53c7c 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -143,7 +143,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) ngx_int_t ngx_http_lua_access_handler_inline(ngx_http_request_t *r) { - char *err; ngx_int_t rc; lua_State *L; ngx_http_lua_loc_conf_t *llcf; @@ -158,17 +157,10 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->access_src.value.data, llcf->access_src.value.len, llcf->access_src_key, - "access_by_lua", &err, + "access_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 12894e01e4..7432a5f5e6 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -156,7 +156,6 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -167,18 +166,11 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) rc = ngx_http_lua_cache_loadbuffer(L, llcf->body_filter_src.value.data, llcf->body_filter_src.value.len, llcf->body_filter_src_key, - "body_filter_by_lua", &err, + "body_filter_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "Failed to load Lua inlined code: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } rc = ngx_http_lua_body_filter_by_chunk(L, r, in); diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 41a4626e5d..3e50da4e38 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -121,10 +121,12 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) ngx_int_t ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, - const u_char *cache_key, const char *name, char **err, - unsigned enabled) + const u_char *cache_key, const char *name, unsigned enabled) { - int rc; + int rc, n; + const char *err = NULL; + + n = lua_gettop(L); dd("XXX cache key: [%s]", cache_key); @@ -142,24 +144,24 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'", cache_key, lua_gettop(L), (int) src_len, src); - /* load closure factory of inline script to the top of lua stack, sp++ */ + /* load closure factory of inline script to the top of lua stack, sp++ */ rc = ngx_http_lua_clfactory_loadbuffer(L, (char *) src, src_len, name); if (rc != 0) { /* Oops! error occured when loading Lua script */ if (rc == LUA_ERRMEM) { - *err = "memory allocation error"; + err = "memory allocation error"; } else { if (lua_isstring(L, -1)) { - *err = (char *) lua_tostring(L, -1); + err = lua_tostring(L, -1); } else { - *err = "unknown error"; + err = "unknown error"; } } - return NGX_ERROR; + goto error; } /* store closure factory and gen new closure at the top of lua stack to @@ -167,11 +169,17 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, rc = ngx_http_lua_cache_store_code(L, (char *) cache_key); if (rc != NGX_OK) { - *err = "fail to generate new closure from the closure factory"; - return NGX_ERROR; + err = "fail to generate new closure from the closure factory"; + goto error; } return NGX_OK; + +error: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "failed to load external Lua file: %s", err); + lua_settop(L, n); + return NGX_ERROR; } diff --git a/src/ngx_http_lua_cache.h b/src/ngx_http_lua_cache.h index a80c7c59b3..1ba0f50e2f 100644 --- a/src/ngx_http_lua_cache.h +++ b/src/ngx_http_lua_cache.h @@ -14,7 +14,7 @@ ngx_int_t ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, const u_char *cache_key, const char *name, - char **err, unsigned enabled); + unsigned enabled); ngx_int_t ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, const u_char *cache_key, unsigned enabled); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 38260b24d5..c635ab72cb 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -271,7 +271,6 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -282,17 +281,10 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->content_src.value.data, llcf->content_src.value.len, llcf->content_src_key, - "content_by_lua", &err, + "content_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 8cdb02f209..7ca72ee354 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -283,7 +283,6 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err = NULL; ngx_http_lua_set_var_data_t *filter_data = data; @@ -296,17 +295,10 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(L, filter_data->script.data, filter_data->script.len, - filter_data->key, "set_by_lua", &err, + filter_data->key, "set_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 4b44390e4e..bf53c4824b 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -143,7 +143,6 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -154,18 +153,11 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->header_filter_src.value.data, llcf->header_filter_src.value.len, llcf->header_filter_src_key, - "header_filter_by_lua", &err, + "header_filter_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } rc = ngx_http_lua_header_filter_by_chunk(L, r); diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 5998fffc67..4fde5d3aa9 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -120,7 +120,6 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; dd("log by lua inline"); @@ -133,17 +132,10 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->log_src.value.data, llcf->log_src.value.len, llcf->log_src_key, "log_by_lua", - &err, llcf->enable_code_cache ? 1 : 0); + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } return ngx_http_lua_log_by_chunk(L, r); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index d33dbfe794..458010f059 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -148,7 +148,6 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; - char *err; dd("rewrite by lua inline"); @@ -161,17 +160,10 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->rewrite_src.value.data, llcf->rewrite_src.value.len, llcf->rewrite_src_key, - "rewrite_by_lua", &err, + "rewrite_by_lua", llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { - if (err == NULL) { - err = "unknown error"; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to load Lua inlined code: %s", err); - return NGX_HTTP_INTERNAL_SERVER_ERROR; } From 2f5ebebcd3f7b63b90ac52e3dfea8d831fe3ee05 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 Aug 2013 13:16:22 -0700 Subject: [PATCH 0175/1981] bugfix: the "connect() failed" error message was still logged even when lua_socket_log_errors was off. thanks Dong Fang Fan for the report. --- src/ngx_http_lua_socket_tcp.c | 23 ++++++++++++++++------- t/058-tcp-socket.t | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index a3eb86ab7d..6258de9f31 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -45,7 +45,8 @@ static void ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_send(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -static ngx_int_t ngx_http_lua_socket_test_connect(ngx_connection_t *c); +static ngx_int_t ngx_http_lua_socket_test_connect(ngx_http_request_t *r, + ngx_connection_t *c); static void ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type); static void ngx_http_lua_socket_handle_success(ngx_http_request_t *r, @@ -2242,7 +2243,7 @@ ngx_http_lua_socket_connected_handler(ngx_http_request_t *r, ngx_del_timer(c->write); } - rc = ngx_http_lua_socket_test_connect(c); + rc = ngx_http_lua_socket_test_connect(r, c); if (rc != NGX_OK) { if (rc > 0) { u->socket_errno = (ngx_err_t) rc; @@ -2371,11 +2372,13 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_socket_test_connect(ngx_connection_t *c) +ngx_http_lua_socket_test_connect(ngx_http_request_t *r, ngx_connection_t *c) { int err; socklen_t len; + ngx_http_lua_loc_conf_t *llcf; + #if (NGX_HAVE_KQUEUE) ngx_event_t *ev; @@ -2395,9 +2398,12 @@ ngx_http_lua_socket_test_connect(ngx_connection_t *c) } if (ev) { - (void) ngx_connection_error(c, ev->kq_errno, - "kevent() reported that connect() " - "failed"); + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_socket_errors) { + (void) ngx_connection_error(c, ev->kq_errno, + "kevent() reported that " + "connect() failed"); + } return ev->kq_errno; } @@ -2419,7 +2425,10 @@ ngx_http_lua_socket_test_connect(ngx_connection_t *c) } if (err) { - (void) ngx_connection_error(c, err, "connect() failed"); + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_socket_errors) { + (void) ngx_connection_error(c, err, "connect() failed"); + } return err; } } diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 2fef1032e6..5720852e55 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 96; +plan tests => repeat_each() * 99; our $HtmlDir = html_dir; @@ -2093,3 +2093,36 @@ run posted requests --- no_error_log [error] + + +=== TEST 35: connection refused (tcp) - lua_socket_log_errors off +--- config + location /test { + lua_socket_log_errors off; + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 16787) + ngx.say("connect: ", ok, " ", err) + + local bytes + bytes, err = sock:send("hello") + ngx.say("send: ", bytes, " ", err) + + local line + line, err = sock:receive() + ngx.say("receive: ", line, " ", err) + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + '; + } +--- request + GET /test +--- response_body +connect: nil connection refused +send: nil closed +receive: nil closed +close: nil closed +--- no_error_log eval +[qr/connect\(\) failed \(\d+: Connection refused\)/] + From 124f50fd4609fb8ffd5885416dced0835cc5a6b2 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 Aug 2013 17:56:35 -0700 Subject: [PATCH 0176/1981] feature: added new method "get_stale" to shared dict objects, which returns the value (if not freed yet) even if the key has already expired. thanks Matthieu Tourne for the patch in #249. --- src/ngx_http_lua_shdict.c | 44 +++++++++++++++++++++++++++++++++++---- t/043-shdict.t | 23 ++++++++++++++++++++ t/062-count.t | 2 +- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index e4caac13ce..7e2f04aa77 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -18,6 +18,8 @@ static int ngx_http_lua_shdict_set(lua_State *L); static int ngx_http_lua_shdict_safe_set(lua_State *L); static int ngx_http_lua_shdict_get(lua_State *L); +static int ngx_http_lua_shdict_get_stale(lua_State *L); +static int ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale); static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n); static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, @@ -291,11 +293,14 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_createtable(L, 0, lmcf->shm_zones->nelts /* nrec */); /* ngx.shared */ - lua_createtable(L, 0 /* narr */, 12 /* nrec */); /* shared mt */ + lua_createtable(L, 0 /* narr */, 13 /* nrec */); /* shared mt */ lua_pushcfunction(L, ngx_http_lua_shdict_get); lua_setfield(L, -2, "get"); + lua_pushcfunction(L, ngx_http_lua_shdict_get_stale); + lua_setfield(L, -2, "get_stale"); + lua_pushcfunction(L, ngx_http_lua_shdict_set); lua_setfield(L, -2, "set"); @@ -355,6 +360,20 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) static int ngx_http_lua_shdict_get(lua_State *L) +{ + return ngx_http_lua_shdict_get_helper(L, 0 /* stale */); +} + + +static int +ngx_http_lua_shdict_get_stale(lua_State *L) +{ + return ngx_http_lua_shdict_get_helper(L, 1 /* stale */); +} + + +static int +ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) { int n; ngx_str_t name; @@ -411,20 +430,22 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 - ngx_http_lua_shdict_expire(ctx, 1); + if (!get_stale) { + ngx_http_lua_shdict_expire(ctx, 1); + } #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returns %d", (int) rc); - if (rc == NGX_DECLINED || rc == NGX_DONE) { + if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); return 1; } - /* rc == NGX_OK */ + /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ value_type = sd->value_type; @@ -485,6 +506,21 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_shmtx_unlock(&ctx->shpool->mutex); + if (get_stale) { + + /* always return value, flags, stale */ + + if (user_flags) { + lua_pushinteger(L, (lua_Integer) user_flags); + + } else { + lua_pushnil(L); + } + + lua_pushboolean(L, rc == NGX_DONE); + return 3; + } + if (user_flags) { lua_pushinteger(L, (lua_Integer) user_flags); return 2; diff --git a/t/043-shdict.t b/t/043-shdict.t index 958228b577..105a76d05a 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1452,3 +1452,26 @@ cur value: hello hello hello hello hello hello hello hello hello hello1 --- no_error_log [error] + + +=== TEST 60: get_stale: expired entries can still be fetched +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("foo", 32, 0.01) + dogs:set("blah", 33, 0.1) + ngx.sleep(0.01) + local val, flags, stale = dogs:get_stale("foo") + ngx.say(val, ", ", flags, ", ", stale) + local val, flags, stale = dogs:get_stale("blah") + ngx.say(val, ", ", flags, ", ", stale) + '; + } +--- request +GET /test +--- response_body +32, nil, true +33, nil, false diff --git a/t/062-count.t b/t/062-count.t index 55b338a88b..35f20d4b82 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -279,7 +279,7 @@ n = 4 --- request GET /test --- response_body -n = 12 +n = 13 --- no_error_log [error] From 424232deb9ad204ee55b5c34567cd55ade2b2926 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 Aug 2013 18:00:00 -0700 Subject: [PATCH 0177/1981] updated docs to reflect recent changes. --- README | 16 ++++++++++++---- README.markdown | 10 ++++++++-- doc/HttpLuaModule.wiki | 10 ++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/README b/README index 922c918775..de89d225b9 100644 --- a/README +++ b/README @@ -1236,8 +1236,8 @@ Directives make room for the current connection. Note that the cosocket connection pool is per nginx worker process - rather than per nginx server instance, so so size limit specified here - also applies to every single nginx worker process. + rather than per nginx server instance, so size limit specified here also + applies to every single nginx worker process. This directive was first introduced in the "v0.5.0rc1" release. @@ -1769,8 +1769,10 @@ Nginx API for Lua res = ngx.location.capture(uri) - Returns a Lua table with three slots ("res.status", "res.header", and - "res.body"). + Returns a Lua table with three slots ("res.status", "res.header", + "res.body", and "res.truncated"). + + "res.status" holds the response status code for the subrequest response. "res.header" holds all the response headers of the subrequest and it is a normal Lua table. For multi-value response headers, the value is a Lua @@ -1785,6 +1787,10 @@ Nginx API for Lua Then "res.header["Set-Cookie"]" will be evaluated to the table value "{"a=3", "foo=bar", "baz=blah"}". + "res.body" holds the subrequest's response body data, which might be + truncated. You always need to check the "res.truncated" boolean flag to + see if "res.body" contains truncated data. + URI query strings can be concatenated to URI itself, for instance, res = ngx.location.capture('/foo/bar?a=3&b=4') @@ -3975,6 +3981,8 @@ Nginx API for Lua ngx.shared.DICT syntax: *dict = ngx.shared.DICT* + syntax: *dict = ngx.shared[name_var]* + context: *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** diff --git a/README.markdown b/README.markdown index b951914f8a..643980a0bd 100644 --- a/README.markdown +++ b/README.markdown @@ -1095,7 +1095,7 @@ Default to 30 connections for every pool. When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. -Note that the cosocket connection pool is per nginx worker process rather than per nginx server instance, so so size limit specified here also applies to every single nginx worker process. +Note that the cosocket connection pool is per nginx worker process rather than per nginx server instance, so size limit specified here also applies to every single nginx worker process. This directive was first introduced in the `v0.5.0rc1` release. @@ -1578,7 +1578,9 @@ Here is a basic example: res = ngx.location.capture(uri) -Returns a Lua table with three slots (`res.status`, `res.header`, and `res.body`). +Returns a Lua table with three slots (`res.status`, `res.header`, `res.body`, and `res.truncated`). + +`res.status` holds the response status code for the subrequest response. `res.header` holds all the response headers of the subrequest and it is a normal Lua table. For multi-value response headers, @@ -1595,6 +1597,8 @@ lines: Then `res.header["Set-Cookie"]` will be evaluated to the table value `{"a=3", "foo=bar", "baz=blah"}`. +`res.body` holds the subrequest's response body data, which might be truncated. You always need to check the `res.truncated` boolean flag to see if `res.body` contains truncated data. + URI query strings can be concatenated to URI itself, for instance, @@ -3683,6 +3687,8 @@ ngx.shared.DICT --------------- **syntax:** *dict = ngx.shared.DICT* +**syntax:** *dict = ngx.shared[name_var]* + **context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](http://wiki.nginx.org/HttpLuaModule#lua_shared_dict) directive. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a19757c41e..4e65a76504 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1055,7 +1055,7 @@ Default to 30 connections for every pool. When the connection pool exceeds the available size limit, the least recently used (idle) connection already in the pool will be closed to make room for the current connection. -Note that the cosocket connection pool is per nginx worker process rather than per nginx server instance, so so size limit specified here also applies to every single nginx worker process. +Note that the cosocket connection pool is per nginx worker process rather than per nginx server instance, so size limit specified here also applies to every single nginx worker process. This directive was first introduced in the v0.5.0rc1 release. @@ -1519,7 +1519,9 @@ Here is a basic example: res = ngx.location.capture(uri) -Returns a Lua table with three slots (res.status, res.header, and res.body). +Returns a Lua table with three slots (res.status, res.header, res.body, and res.truncated). + +res.status holds the response status code for the subrequest response. res.header holds all the response headers of the subrequest and it is a normal Lua table. For multi-value response headers, @@ -1536,6 +1538,8 @@ lines: Then res.header["Set-Cookie"] will be evaluated to the table value {"a=3", "foo=bar", "baz=blah"}. +res.body holds the subrequest's response body data, which might be truncated. You always need to check the res.truncated boolean flag to see if res.body contains truncated data. + URI query strings can be concatenated to URI itself, for instance, @@ -3560,6 +3564,8 @@ This feature was first introduced in the v0.2.1rc15 release. == ngx.shared.DICT == '''syntax:''' ''dict = ngx.shared.DICT'' +'''syntax:''' ''dict = ngx.shared[name_var]'' + '''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. From 87a4f346b85699cfb06a2c8756af6fabbf87d904 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 Aug 2013 18:07:00 -0700 Subject: [PATCH 0178/1981] documented the new "get_stale" method for shdict objects. --- README | 21 +++++++++++++++++++++ README.markdown | 17 +++++++++++++++++ doc/HttpLuaModule.wiki | 16 ++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/README b/README index de89d225b9..64aa1f3ed7 100644 --- a/README +++ b/README @@ -3994,6 +3994,8 @@ Nginx API for Lua * get + * get_stale + * set * safe_set @@ -4092,6 +4094,25 @@ Nginx API for Lua See also ngx.shared.DICT. + ngx.shared.DICT.get_stale + syntax: *value, flags, stale = ngx.shared.DICT:get_stale(key)* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + + Similar to the get method but returns the value even if the key has + already expired. + + Returns a 3rd value, "stale", indicating whether the key has expired or + not. + + Note that the value of an expired key is not guaranteed to be available + so one should never rely on the availability of expired items. + + This method was first introduced in the 0.8.6 release. + + See also ngx.shared.DICT. + ngx.shared.DICT.set syntax: *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* diff --git a/README.markdown b/README.markdown index 643980a0bd..41708e717a 100644 --- a/README.markdown +++ b/README.markdown @@ -3696,6 +3696,7 @@ Fetching the shm-based Lua dictionary object for the shared memory zone named `D The resulting object `dict` has the following methods: * [get](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.get) +* [get_stale](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.get_stale) * [set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.set) * [safe_set](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.safe_set) * [add](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.add) @@ -3782,6 +3783,22 @@ This feature was first introduced in the `v0.3.1rc22` release. See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). +ngx.shared.DICT.get_stale +------------------------- +**syntax:** *value, flags, stale = ngx.shared.DICT:get_stale(key)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** + +Similar to the [get](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT.get) method but returns the value even if the key has already expired. + +Returns a 3rd value, `stale`, indicating whether the key has expired or not. + +Note that the value of an expired key is not guaranteed to be available so one should never rely on the availability of expired items. + +This method was first introduced in the `0.8.6` release. + +See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). + ngx.shared.DICT.set ------------------- **syntax:** *success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 4e65a76504..207d1fafc7 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3573,6 +3573,7 @@ Fetching the shm-based Lua dictionary object for the shared memory zone named dict has the following methods: * [[#ngx.shared.DICT.get|get]] +* [[#ngx.shared.DICT.get_stale|get_stale]] * [[#ngx.shared.DICT.set|set]] * [[#ngx.shared.DICT.safe_set|safe_set]] * [[#ngx.shared.DICT.add|add]] @@ -3658,6 +3659,21 @@ This feature was first introduced in the v0.3.1rc22 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. +== ngx.shared.DICT.get_stale == +'''syntax:''' ''value, flags, stale = ngx.shared.DICT:get_stale(key)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*'' + +Similar to the [[#ngx.shared.DICT.get|get]] method but returns the value even if the key has already expired. + +Returns a 3rd value, stale, indicating whether the key has expired or not. + +Note that the value of an expired key is not guaranteed to be available so one should never rely on the availability of expired items. + +This method was first introduced in the 0.8.6 release. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.set == '''syntax:''' ''success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)'' From e0626c31275dd9892a3946493e3434fdd21edbb6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 Aug 2013 19:00:11 -0700 Subject: [PATCH 0179/1981] added tests to improve the code coverage in file ngx_http_lua_headers_out.c. --- t/016-resp-header.t | 102 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/t/016-resp-header.t b/t/016-resp-header.t index eb39fe4dc5..435a49b22f 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -854,3 +854,105 @@ content_type: anything --- no_error_log [error] + + +=== TEST 43: set multiple response header +--- config + location /read { + content_by_lua ' + for i = 1, 50 do + ngx.header["X-Direct-" .. i] = "text/my-plain-" .. i; + end + + ngx.say(ngx.header["X-Direct-50"]); + '; + } +--- request +GET /read +--- response_body +text/my-plain-50 +--- no_error_log +[error] + + + +=== TEST 44: set multiple response header and then reset and then clear +--- config + location /read { + content_by_lua ' + for i = 1, 50 do + ngx.header["X-Direct-" .. i] = "text/my-plain-" .. i; + end + + for i = 1, 50 do + ngx.header["X-Direct-" .. i] = "text/my-plain" + end + + for i = 1, 50 do + ngx.header["X-Direct-" .. i] = nil + end + + ngx.say("ok"); + '; + } +--- request +GET /read +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 45: set response content-type header for multiple times +--- config + location /read { + content_by_lua ' + ngx.header.content_type = "text/my-plain"; + ngx.header.content_type = "text/my-plain-2"; + ngx.say("Hi"); + '; + } +--- request +GET /read +--- response_headers +Content-Type: text/my-plain-2 +--- response_body +Hi + + + +=== TEST 46: set Last-Modified response header for multiple times +--- config + location /read { + content_by_lua ' + ngx.header.last_modified = ngx.http_time(1290079655) + ngx.header.last_modified = ngx.http_time(1290079654) + ngx.say("ok"); + '; + } +--- request +GET /read +--- response_headers +Last-Modified: Thu, 18 Nov 2010 11:27:34 GMT +--- response_body +ok + + + +=== TEST 47: set Last-Modified response header and then clear +--- config + location /read { + content_by_lua ' + ngx.header.last_modified = ngx.http_time(1290079655) + ngx.header.last_modified = nil + ngx.say("ok"); + '; + } +--- request +GET /read +--- response_headers +!Last-Modified +--- response_body +ok + From 547d299463d95e33af7131fef82c39d4a72e7a35 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 2 Aug 2013 19:16:05 -0700 Subject: [PATCH 0180/1981] bugfix: segfault might happen when reading or writing to a response header via the ngx.header.HEADER API in the case that the nginx core initiated a 301 redirect. this issue was caused by an optimization in the nginx core where ngx_http_core_find_config_phase, for example, does not fully initialize the "Location" response header after creating the header. thanks Vladimir Protasov for the report in #260. --- src/ngx_http_lua_headers_out.c | 34 +++++++++++++++++++++++++-- t/016-resp-header.t | 42 +++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 0d34337769..bb061f9404 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -132,6 +132,20 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, goto new_header; } +#if 1 + if (r->headers_out.location + && r->headers_out.location->value.len + && r->headers_out.location->value.data[0] == '/') + { + /* XXX ngx_http_core_find_config_phase, for example, + * may not initialize the "key" and "hash" fields + * for a nasty optimization purpose, and + * we have to work-around it here */ + + r->headers_out.location->hash = 0; + } +#endif + part = &r->headers_out.headers.part; h = part->elts; @@ -146,7 +160,8 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, i = 0; } - if (h[i].key.len == hv->key.len + if (h[i].hash != 0 + && h[i].key.len == hv->key.len && ngx_strncasecmp(hv->key.data, h[i].key.data, h[i].key.len) == 0) { dd("found out header %.*s", (int) h[i].key.len, h[i].key.data); @@ -503,6 +518,20 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, found = 0; +#if 1 + if (r->headers_out.location + && r->headers_out.location->value.len + && r->headers_out.location->value.data[0] == '/') + { + /* XXX ngx_http_core_find_config_phase, for example, + * may not initialize the "key" and "hash" fields + * for a nasty optimization purpose, and + * we have to work-around it here */ + + r->headers_out.location->hash = 0; + } +#endif + part = &r->headers_out.headers.part; h = part->elts; @@ -521,7 +550,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, continue; } - if (h[i].key.len == key->len + if (h[i].hash != 0 + && h[i].key.len == key->len && ngx_strncasecmp(key->data, h[i].key.data, h[i].key.len) == 0) { if (!found) { diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 435a49b22f..49ddbf3582 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -658,7 +658,7 @@ Cache-Control: no-cache ngx.header.cache_control = { "private", "no-store" } ngx.header.cache_control = { "no-cache", "blah", "foo" } ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) - ngx.say("Cache-Control: ", table.concat(ngx.header.cache_control, "; ")) + ngx.say("Cache-Control: ", table.concat(ngx.header.cache_control, ", ")) '; } --- request @@ -956,3 +956,43 @@ GET /read --- response_body ok + + +=== TEST 48: github #20: segfault caused by the nasty optimization in the nginx core (write) +--- config + location = /t/ { + header_filter_by_lua ' + ngx.header.foo = 1 + '; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 49: github #20: segfault caused by the nasty optimization in the nginx core (read) +--- config + location = /t/ { + header_filter_by_lua ' + local v = ngx.header.foo + '; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + From 7dbd2a5118f36ef039b79a87ef5f00f19d593f7c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 3 Aug 2013 22:28:09 -0700 Subject: [PATCH 0181/1981] bugfix: reading ngx.header.location did not work when auto-redirect was in action. this is a further fix for #260. --- src/ngx_http_lua_headers_out.c | 12 ++++++-- t/016-resp-header.t | 53 +++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index bb061f9404..0b78b08265 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -142,7 +142,11 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, * for a nasty optimization purpose, and * we have to work-around it here */ - r->headers_out.location->hash = 0; + r->headers_out.location->hash = + ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( + ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); + + ngx_str_set(&r->headers_out.location->key, "Location"); } #endif @@ -528,7 +532,11 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, * for a nasty optimization purpose, and * we have to work-around it here */ - r->headers_out.location->hash = 0; + r->headers_out.location->hash = + ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( + ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); + + ngx_str_set(&r->headers_out.location->key, "Location"); } #endif diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 49ddbf3582..135aa082d4 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 2); +plan tests => repeat_each() * (blocks() * 3 + 8); #no_diff(); no_long_string(); @@ -971,6 +971,8 @@ GET /t --- more_headers Foo: bar Bah: baz +--- response_headers +Location: http://localhost:$ServerPort/t/ --- response_body_like: 301 Moved Permanently --- error_code: 301 --- no_error_log @@ -992,6 +994,55 @@ GET /t Foo: bar Bah: baz --- response_body_like: 301 Moved Permanently +--- response_headers +Location: http://localhost:$ServerPort/t/ +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 50: github #20: segfault caused by the nasty optimization in the nginx core (read Location) +--- config + location = /t/ { + header_filter_by_lua ' + ngx.header.Foo = ngx.header.location + '; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_headers +Location: http://localhost:$ServerPort/t/ +Foo: /t/ +--- response_body_like: 301 Moved Permanently +--- error_code: 301 +--- no_error_log +[error] + + + +=== TEST 51: github #20: segfault caused by the nasty optimization in the nginx core (set Foo and read Location) +--- config + location = /t/ { + header_filter_by_lua ' + ngx.header.Foo = 3 + ngx.header.Foo = ngx.header.location + '; + proxy_pass http://127.0.0.1:$server_port; + } +--- request +GET /t +--- more_headers +Foo: bar +Bah: baz +--- response_headers +Location: http://localhost:$ServerPort/t/ +Foo: /t/ +--- response_body_like: 301 Moved Permanently --- error_code: 301 --- no_error_log [error] From c7237efd8a43bf07d5fde8828594084160fe49de Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 4 Aug 2013 00:44:36 -0700 Subject: [PATCH 0182/1981] made the test for shdict:get_stale less possible to fail. --- t/043-shdict.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/043-shdict.t b/t/043-shdict.t index 105a76d05a..3b46dea15a 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1463,7 +1463,7 @@ cur value: hello hello hello hello hello hello hello hello hello hello1 local dogs = ngx.shared.dogs dogs:set("foo", 32, 0.01) dogs:set("blah", 33, 0.1) - ngx.sleep(0.01) + ngx.sleep(0.02) local val, flags, stale = dogs:get_stale("foo") ngx.say(val, ", ", flags, ", ", stale) local val, flags, stale = dogs:get_stale("blah") From e72ab1dba54084e9e527f14288be7f167d06ce2b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 4 Aug 2013 00:49:02 -0700 Subject: [PATCH 0183/1981] minor coding style fixes. --- src/ngx_http_lua_headers_out.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 0b78b08265..29bfc46fc7 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -154,6 +154,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, h = part->elts; for (i = 0; /* void */; i++) { + if (i >= part->nelts) { if (part->next == NULL) { break; @@ -544,6 +545,7 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, h = part->elts; for (i = 0; /* void */; i++) { + if (i >= part->nelts) { if (part->next == NULL) { break; From 65d4b419bf531c156b542fcd180e9aadb9439e34 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 4 Aug 2013 10:21:26 -0700 Subject: [PATCH 0184/1981] minor test fixes. --- t/005-exit.t | 2 +- t/023-rewrite/exit.t | 2 +- t/024-access/exit.t | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/005-exit.t b/t/005-exit.t index c201ed4137..24806b6d62 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -429,7 +429,7 @@ GET /baz --- response_body_like: 302 --- error_code: 302 --- response_headers -Location: http://localhost:1984/foo/bar +Location: http://localhost:$ServerPort/foo/bar --- SKIP diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 11aa1335a5..9be5312994 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -426,7 +426,7 @@ GET /baz --- response_body_like: 302 --- error_code: 302 --- response_headers -Location: http://localhost:1984/foo/bar +Location: http://localhost:$ServerPort/foo/bar --- SKIP diff --git a/t/024-access/exit.t b/t/024-access/exit.t index 2cb1d4af09..4083e090b1 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -404,7 +404,7 @@ GET /baz --- response_body_like: 302 --- error_code: 302 --- response_headers -Location: http://localhost:1984/foo/bar +Location: http://localhost:$ServerPort/foo/bar --- SKIP From 2db5028ad803fdb2b7ada0eb459cf7853c2c069b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 6 Aug 2013 12:47:26 -0700 Subject: [PATCH 0185/1981] bugfix: segfaults would happen in ngx.req.set_header() and ngx.req.clear_header() for HTTP 0.9 requests. thanks Bin Wang for the report in agentzh/headers-more-nginx-module#14. --- src/ngx_http_lua_headers.c | 4 ++++ t/028-req-header.t | 42 +++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 925132b6cc..82b7e3d823 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -604,6 +604,10 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) ngx_http_lua_check_fake_request(L, r); + if (r->http_version < NGX_HTTP_VERSION_10) { + return 0; + } + p = (u_char *) luaL_checklstring(L, 1, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); diff --git a/t/028-req-header.t b/t/028-req-header.t index c49fcfeb78..dff3dd8c3c 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 14); +plan tests => repeat_each() * (2 * blocks() + 18); #no_diff(); #no_long_string(); @@ -1269,3 +1269,43 @@ foo_bar: some value\r \r $} + + +=== TEST 40: HTTP 0.9 (set & get) +--- config + location /foo { + content_by_lua ' + ngx.req.set_header("X-Foo", "howdy"); + ngx.say("X-Foo: ", ngx.req.get_headers()["X-Foo"]) + '; + } +--- raw_request eval +"GET /foo\r\n" +--- response_headers +! X-Foo +--- response_body +X-Foo: nil +--- http09 +--- no_error_log +[error] + + + +=== TEST 41: HTTP 0.9 (clear) +--- config + location /foo { + content_by_lua ' + ngx.req.set_header("X-Foo", "howdy"); + ngx.say("X-Foo: ", ngx.req.get_headers()["X-Foo"]) + '; + } +--- raw_request eval +"GET /foo\r\n" +--- response_headers +! X-Foo +--- response_body +X-Foo: nil +--- http09 +--- no_error_log +[error] + From 940429a5c6b2a2350635c3f48b6dac751e0b07c2 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 6 Aug 2013 16:21:39 -0700 Subject: [PATCH 0186/1981] bumped version to 0.8.6. --- README | 6 +++--- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README b/README index 64aa1f3ed7..ee4ced47d8 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.5 - () released on 18 - July 2013. + This document describes ngx_lua v0.8.6 + () released on 6 + August 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): diff --git a/README.markdown b/README.markdown index 41708e717a..cbb12efa62 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 18 July 2013. +This document describes ngx_lua [v0.8.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 6 August 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 207d1fafc7..6fb4ce21e3 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.5] released on 18 July 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.6] released on 6 August 2013. = Synopsis = From 4042f7bd63db31177f1177ad49c8baa9163bbbfb Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 14 Aug 2013 11:49:42 -0700 Subject: [PATCH 0187/1981] bugfix: ngx.flush() triggered response header sending when the header was not sent yet. now it just returned the error string "nothing to flush" for this case. thanks linbo liao for the report. --- src/ngx_http_lua_output.c | 8 ++++++++ t/056-flush.t | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index f58dcada67..8be60a258b 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -514,6 +514,14 @@ ngx_http_lua_ngx_flush(lua_State *L) return 2; } +#if 1 + if (!ctx->headers_sent) { + lua_pushnil(L); + lua_pushliteral(L, "nothing to flush"); + return 2; + } +#endif + if (ctx->flush_buf) { cl = ctx->flush_buf; diff --git a/t/056-flush.t b/t/056-flush.t index 25900573b8..ae0bb12127 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -14,7 +14,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 45; +plan tests => repeat_each() * 50; #no_diff(); no_long_string(); @@ -136,9 +136,15 @@ lua http 1.0 buffering makes ngx.flush() a no-op location /test { content_by_lua ' ngx.say("hello, world") - ngx.flush(false) + local ok, err = ngx.flush(false) + if not ok then + ngx.log(ngx.WARN, "1: failed to flush: ", err) + end ngx.say("hiya") - ngx.flush(false) + local ok, err = ngx.flush(false) + if not ok then + ngx.log(ngx.WARN, "2: failed to flush: ", err) + end ngx.say("blah") '; } @@ -153,6 +159,8 @@ Content-Length: 23 --- error_log lua buffering output bufs for the HTTP 1.0 request lua http 1.0 buffering makes ngx.flush() a no-op +1: failed to flush: buffering +2: failed to flush: buffering --- timeout: 5 @@ -400,3 +408,22 @@ true --- error_log lua reuse free buf memory 13 >= 5 + + +=== TEST 14: flush before sending out the header +--- config + location /test { + content_by_lua ' + ngx.flush() + ngx.status = 404 + ngx.say("not found") + '; + } +--- request +GET /test +--- response_body +not found +--- error_code: 404 +--- no_error_log +[error] + From b3734f0020a09fa9bdef1ad39088a5b292a678dd Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 25 Aug 2013 10:54:55 -0700 Subject: [PATCH 0188/1981] bugfix: the global Lua state's _G table was cleared when lua_code_cache was off, which could confuse the setup in init_by_lua. thanks Robert Andrew Ditthardt for the report in #257. --- src/ngx_http_lua_cache.c | 2 ++ t/025-codecache.t | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 3e50da4e38..508bceb07b 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -406,8 +406,10 @@ ngx_http_lua_clear_package_loaded(lua_State *L) /* package loaded */ lua_pop(L, 2); +#if 0 lua_newtable(L); lua_setglobal(L, "_G"); +#endif } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/025-codecache.t b/t/025-codecache.t index 97b3f1b036..71278140a1 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 1); #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -588,3 +588,30 @@ found --- response_body _G.foo: 1 + + +=== TEST 1: github #257: globals cleared when code cache off +--- http_config + lua_code_cache off; + init_by_lua ' + test = setfenv( + function() + ngx.say(tostring(table)) + end, + setmetatable({}, + { + __index = function(self, key) + return rawget(self, key) or _G[key] + end + }))'; +--- config + location = /t { + content_by_lua 'test()'; + } +--- request +GET /t +--- response_body_like chop +^table: 0x[1-9a-fA-F] +--- no_error_log +[error] + From 334afb35d616560eba4680143b059031a16cb571 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 26 Aug 2013 18:50:10 -0700 Subject: [PATCH 0189/1981] fixed a test case index number in 025-codecache.t. --- t/025-codecache.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/025-codecache.t b/t/025-codecache.t index 71278140a1..fa0231a177 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -590,7 +590,7 @@ _G.foo: 1 -=== TEST 1: github #257: globals cleared when code cache off +=== TEST 18: github #257: globals cleared when code cache off --- http_config lua_code_cache off; init_by_lua ' From e549fc2df0c03648a4553c8310c90c61db46aa42 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 26 Aug 2013 18:57:45 -0700 Subject: [PATCH 0190/1981] feature: log_by_lua now always runs before the standard ngx_http_log_module (for access logging). thanks Calin Don for the suggestion in #254. --- src/ngx_http_lua_module.c | 10 +++++++++- t/075-logby.t | 29 ++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 63d4f7f9eb..2f3ecdfb42 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -382,6 +382,7 @@ static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf) { ngx_int_t rc; + ngx_array_t *arr; ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; ngx_http_lua_main_conf_t *lmcf; @@ -422,11 +423,18 @@ ngx_http_lua_init(ngx_conf_t *cf) dd("requires log: %d", (int) lmcf->requires_log); if (lmcf->requires_log) { - h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); + arr = &cmcf->phases[NGX_HTTP_LOG_PHASE].handlers; + h = ngx_array_push(arr); if (h == NULL) { return NGX_ERROR; } + if (arr->nelts > 1) { + h = arr->elts; + ngx_memmove(&h[1], h, + (arr->nelts - 1) * sizeof(ngx_http_handler_pt)); + } + *h = ngx_http_lua_log_handler; } diff --git a/t/075-logby.t b/t/075-logby.t index b7ba08835f..03b1de5647 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 8); +plan tests => repeat_each() * (blocks() * 3 + 9); #no_diff(); #no_long_string(); @@ -537,3 +537,30 @@ ok --- error_log eval qr/failed to load external Lua file: cannot open .*? No such file or directory/ + + +=== TEST 30: log_by_lua runs before access logging (github issue #254) +--- config + location /lua { + echo ok; + access_log logs/foo.log; + log_by_lua 'print("hello")'; + } +--- request +GET /lua +--- stap +F(ngx_http_log_handler) { + println("log handler") +} +F(ngx_http_lua_log_handler) { + println("lua log handler") +} +--- stap_out +lua log handler +log handler + +--- response_body +ok +--- no_error_log +[error] + From f4c4667b513fb41d0a571a60961e4b07fe32591f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 16:10:36 -0700 Subject: [PATCH 0191/1981] fixed a potential test failure in a recently added test case in 025-codecache.t. --- t/025-codecache.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/025-codecache.t b/t/025-codecache.t index fa0231a177..0ee1ea8998 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -611,7 +611,7 @@ _G.foo: 1 --- request GET /t --- response_body_like chop -^table: 0x[1-9a-fA-F] +^table: 0x\d*?[1-9a-fA-F] --- no_error_log [error] From a0343434b84e02405c0b91ecfef617d8b446a0ee Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:41:48 -0700 Subject: [PATCH 0192/1981] bugfix: ngx.exit(204) could try to send the response header for twice. nginx 1.5.4 caught this issue. --- src/ngx_http_lua_util.c | 3 ++- t/023-rewrite/exit.t | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1b9d24c60a..a90825fb9f 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2203,7 +2203,8 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, if ((ctx->exit_code == NGX_OK && ctx->entered_content_phase) || (ctx->exit_code >= NGX_HTTP_OK - && ctx->exit_code < NGX_HTTP_SPECIAL_RESPONSE)) + && ctx->exit_code < NGX_HTTP_SPECIAL_RESPONSE + && ctx->exit_code != NGX_HTTP_NO_CONTENT)) { rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 9be5312994..67b5d4bf17 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -13,7 +13,7 @@ repeat_each(2); #log_level('warn'); #worker_connections(1024); -plan tests => repeat_each() * (blocks() * 2 + 3); +plan tests => repeat_each() * (blocks() * 2 + 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -543,7 +543,7 @@ This is our own content -=== TEST 17: encode args table with a multi-value arg. +=== TEST 17: exit with 204 (HTTP 1.1) --- config location = /t { rewrite_by_lua ' @@ -559,6 +559,39 @@ This is our own content --- request GET /t --- more_headers2 +--- stap2 +F(ngx_http_send_header) { + printf("send header\n") + print_ubacktrace() +} +--- response_body +--- error_code: 204 +--- no_error_log +[error] + + + +=== TEST 18: exit with 204 (HTTP 1.0) +--- config + location = /t { + rewrite_by_lua ' + ngx.exit(204) + '; + + proxy_pass http://127.0.0.1:$server_port/blah; + } + + location = /blah { + echo blah; + } +--- request +GET /t HTTP/1.0 +--- more_headers2 +--- stap2 +F(ngx_http_send_header) { + printf("send header\n") + print_ubacktrace() +} --- response_body --- error_code: 204 --- no_error_log From d9a48d86cfaa3ca07073e0559c8a4e01a86f495a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:46:26 -0700 Subject: [PATCH 0193/1981] bugfix: the error message for failures in loading inlined Lua code was misleading. --- src/ngx_http_lua_cache.c | 2 +- t/002-content.t | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 508bceb07b..85332edd0d 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -177,7 +177,7 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, error: ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "failed to load external Lua file: %s", err); + "failed to load inlined Lua code: %s", err); lua_settop(L, n); return NGX_ERROR; } diff --git a/t/002-content.t b/t/002-content.t index b273492fe9..bfc08b87b7 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 17); +plan tests => repeat_each() * (blocks() * 2 + 18); #no_diff(); #no_long_string(); @@ -821,3 +821,21 @@ line 3 --- no_error_log [error] + + +=== TEST 42: syntax error in inlined Lua code +--- config + location /lua { + content_by_lua 'for end'; + } +--- 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 inlined Lua code: / + From c9a04a9c2cc6715246979be9a4ef3351479ad5b6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:53:24 -0700 Subject: [PATCH 0194/1981] bugfix: when a Lua line comment was used in the last line of the inlined Lua code chunk, a bogus Lua syntax error would be thrown. --- src/ngx_http_lua_clfactory.h | 2 +- t/014-bugs.t | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_clfactory.h b/src/ngx_http_lua_clfactory.h index beecb3d5ea..4d0e1cef92 100644 --- a/src/ngx_http_lua_clfactory.h +++ b/src/ngx_http_lua_clfactory.h @@ -15,7 +15,7 @@ #define CLFACTORY_BEGIN_CODE "return function() " #define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE)-1) -#define CLFACTORY_END_CODE " end" +#define CLFACTORY_END_CODE "\nend" #define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE)-1) diff --git a/t/014-bugs.t b/t/014-bugs.t index 486096e057..dd6ec24088 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -9,7 +9,7 @@ log_level('debug'); repeat_each(3); -plan tests => repeat_each() * (blocks() * 2 + 23); +plan tests => repeat_each() * (blocks() * 2 + 24); our $HtmlDir = html_dir; #warn $html_dir; @@ -814,3 +814,17 @@ Hello, 502 not-exist.agentzh.org could not be resolved --- timeout: 3 + + +=== TEST 36: line comments in the last line of the inlined Lua code +--- config + location /lua { + content_by_lua 'ngx.say("ok") -- blah'; + } +--- request +GET /lua +--- response_body +ok +--- no_error_log +[error] + From 1e13a16b3484072c41a8a5db704fe818d4a22125 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:55:19 -0700 Subject: [PATCH 0195/1981] minor refactoring in the closure factory. --- src/ngx_http_lua_clfactory.c | 7 +++++++ src/ngx_http_lua_clfactory.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index decb7ea6b4..778bb22d69 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -15,6 +15,13 @@ #include "ngx_http_lua_clfactory.h" +#define CLFACTORY_BEGIN_CODE "return function() " +#define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1) + +#define CLFACTORY_END_CODE "\nend" +#define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1) + + /* * taken from chaoslawful: * Lua bytecode header Luajit bytecode header diff --git a/src/ngx_http_lua_clfactory.h b/src/ngx_http_lua_clfactory.h index 4d0e1cef92..7c1a4c3e1a 100644 --- a/src/ngx_http_lua_clfactory.h +++ b/src/ngx_http_lua_clfactory.h @@ -12,13 +12,6 @@ #include "ngx_http_lua_common.h" -#define CLFACTORY_BEGIN_CODE "return function() " -#define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE)-1) - -#define CLFACTORY_END_CODE "\nend" -#define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE)-1) - - int ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename); int ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, size_t size, const char *name); From 3e049c59450fe7cd8f8bcc710c161fd7b0fc3b3e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:56:02 -0700 Subject: [PATCH 0196/1981] minor cleanup in a recently added test case. --- t/002-content.t | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/t/002-content.t b/t/002-content.t index bfc08b87b7..889711ff1c 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -828,12 +828,8 @@ line 3 location /lua { content_by_lua 'for end'; } ---- user_files ->>> test.lua -v = ngx.var["request_uri"] -ngx.print("request_uri: ", v, "\n") --- request -GET /lua?a=1&b=2 +GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval From fdec2703561d92254fbe85b83808fa2f705abd69 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 Aug 2013 23:58:43 -0700 Subject: [PATCH 0197/1981] fixed test cases that tried to send the response header twice, which were caught by nginx 1.5.4. --- t/023-rewrite/sanity.t | 8 +++++--- t/024-access/sanity.t | 4 ++-- t/030-uri-args.t | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t index 39f473f043..e98e3c0481 100644 --- a/t/023-rewrite/sanity.t +++ b/t/023-rewrite/sanity.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 9); #no_diff(); #no_long_string(); @@ -646,13 +646,15 @@ bah === TEST 33: server rewrite_by_lua --- config - rewrite_by_lua 'ngx.header["X-Foo"] = "bar" ngx.send_headers()'; + rewrite_by_lua 'ngx.header["X-Foo"] = "bar" -- ngx.send_headers()'; --- request GET / --- response_body chop It works!It works! --- response_headers X-Foo: bar +--- no_error_log +[error] @@ -661,7 +663,7 @@ X-Foo: bar rewrite_by_lua_file html/foo.lua; --- user_files >>> foo.lua -ngx.header["X-Foo"] = "bar" ngx.send_headers() +ngx.header["X-Foo"] = "bar" -- ngx.send_headers() --- request GET / --- response_body chop diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 856d5b4156..01438bd932 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -657,7 +657,7 @@ GET /main === TEST 34: server access_by_lua --- config - access_by_lua 'ngx.header["X-Foo"] = "bar" ngx.send_headers()'; + access_by_lua 'ngx.header["X-Foo"] = "bar" -- ngx.send_headers()'; --- request GET / --- response_body chop @@ -672,7 +672,7 @@ X-Foo: bar access_by_lua_file html/foo.lua; --- user_files >>> foo.lua -ngx.header["X-Foo"] = "bar" ngx.send_headers() +ngx.header["X-Foo"] = "bar" -- ngx.send_headers() --- request GET / --- response_body chop diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 2b1019f7ee..71c24bcc48 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -437,7 +437,9 @@ foo: /bar?hello local res, err = pcall(ngx.req.set_uri, "") ngx.say("err: ", err) '; - echo "foo: $uri?$args"; + content_by_lua ' + ngx.say("foo: ", ngx.var.uri, "?", ngx.var.args) + '; } --- request GET /foo?world From 9577e5fc58a20a553ca01fd3d736ab80dc722870 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 31 Aug 2013 17:30:33 -0700 Subject: [PATCH 0198/1981] feature: added new API ngx.config.debug to indicate whether this is a debug build of nginx. --- config | 2 ++ src/ngx_http_lua_config.c | 32 ++++++++++++++++++++++++++++++++ src/ngx_http_lua_config.h | 19 +++++++++++++++++++ src/ngx_http_lua_util.c | 2 ++ t/114-config.t | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 src/ngx_http_lua_config.c create mode 100644 src/ngx_http_lua_config.h create mode 100644 t/114-config.t diff --git a/config b/config index a7e13bc4cd..84f717218f 100644 --- a/config +++ b/config @@ -222,6 +222,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_phase.c \ $ngx_addon_dir/src/ngx_http_lua_uthread.c \ $ngx_addon_dir/src/ngx_http_lua_timer.c \ + $ngx_addon_dir/src/ngx_http_lua_config.c \ " NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ @@ -272,6 +273,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_probe.h \ $ngx_addon_dir/src/ngx_http_lua_uthread.h \ $ngx_addon_dir/src/ngx_http_lua_timer.h \ + $ngx_addon_dir/src/ngx_http_lua_config.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/src/ngx_http_lua_config.c b/src/ngx_http_lua_config.c new file mode 100644 index 0000000000..38e20b960c --- /dev/null +++ b/src/ngx_http_lua_config.c @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_config.h" + + +void +ngx_http_lua_inject_config_api(lua_State *L) +{ + /* ngx.config */ + + lua_newtable(L); /* .config */ + +#if (NGX_DEBUG) + lua_pushboolean(L, 1); +#else + lua_pushboolean(L, 0); +#endif + + lua_setfield(L, -2, "debug"); + + lua_setfield(L, -2, "config"); +} diff --git a/src/ngx_http_lua_config.h b/src/ngx_http_lua_config.h new file mode 100644 index 0000000000..9f85f31b3c --- /dev/null +++ b/src/ngx_http_lua_config.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ +#define _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +void ngx_http_lua_inject_config_api(lua_State *L); + + +#endif /* _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a90825fb9f..33ac849ce1 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -46,6 +46,7 @@ #include "ngx_http_lua_uthread.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_timer.h" +#include "ngx_http_lua_config.h" #if 1 @@ -770,6 +771,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) ngx_http_lua_inject_socket_udp_api(cf->log, L); ngx_http_lua_inject_uthread_api(cf->log, L); ngx_http_lua_inject_timer_api(L); + ngx_http_lua_inject_config_api(L); ngx_http_lua_inject_misc_api(L); diff --git a/t/114-config.t b/t/114-config.t new file mode 100644 index 0000000000..3a3f9d27c5 --- /dev/null +++ b/t/114-config.t @@ -0,0 +1,33 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use t::TestNginxLua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ngx.config.debug +--- config + location /t { + content_by_lua ' + ngx.say("debug: ", ngx.config.debug) + '; + } +--- request +GET /t +--- response_body_like chop +^debug: (?:true|false)$ +--- no_error_log +[error] + From c752049275cb65f054c92e81239e21b81c85a5ec Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 31 Aug 2013 17:34:36 -0700 Subject: [PATCH 0199/1981] optimize: fixed the initial table sizes for "ngx", "ngx.config", and "ngx.re". --- src/ngx_http_lua_config.c | 2 +- src/ngx_http_lua_regex.c | 2 +- src/ngx_http_lua_util.c | 2 +- t/062-count.t | 48 +++++++++++++++++++++++++++++++++++---- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_config.c b/src/ngx_http_lua_config.c index 38e20b960c..e79ba69ec6 100644 --- a/src/ngx_http_lua_config.c +++ b/src/ngx_http_lua_config.c @@ -18,7 +18,7 @@ ngx_http_lua_inject_config_api(lua_State *L) { /* ngx.config */ - lua_newtable(L); /* .config */ + lua_createtable(L, 0, 1 /* nrec */); /* .config */ #if (NGX_DEBUG) lua_pushboolean(L, 1); diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 593fae8ea9..bd385643cb 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1807,7 +1807,7 @@ ngx_http_lua_inject_regex_api(lua_State *L) { /* ngx.re */ - lua_newtable(L); /* .re */ + lua_createtable(L, 0, 4 /* nrec */); /* .re */ lua_pushcfunction(L, ngx_http_lua_ngx_re_match); lua_setfield(L, -2, "match"); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 33ac849ce1..81c671bcf9 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -743,7 +743,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - lua_createtable(L, 0 /* narr */, 95 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 96 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); diff --git a/t/062-count.t b/t/062-count.t index 35f20d4b82..f425b8e4a8 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 95 +ngx: 96 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 95 --- request GET /test --- response_body -95 +96 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 95 +n = 96 --- no_error_log [error] @@ -301,7 +301,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 95 +ngx. entry count: 96 @@ -323,3 +323,43 @@ n = 1 --- no_error_log [error] + + +=== TEST 15: entries under ngx.config +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(ngx.config) do + n = n + 1 + end + ngx.say("n = ", n) + '; + } +--- request +GET /test +--- response_body +n = 1 +--- no_error_log +[error] + + + +=== TEST 16: entries under ngx.re +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(ngx.re) do + n = n + 1 + end + ngx.say("n = ", n) + '; + } +--- request +GET /test +--- response_body +n = 4 +--- no_error_log +[error] + From 65010dd0917119804809df33c807a72adf98216c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 31 Aug 2013 19:06:21 -0700 Subject: [PATCH 0200/1981] feature: added support for lua_regex_match_limit in the FFI C API function for PCRE. --- src/ngx_http_lua_regex.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index c738883933..84943e9e38 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2013,6 +2013,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, pcre_extra *sd = NULL; ngx_http_lua_regex_t *re; + ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_regex_compile_t re_comp; pool = ngx_create_pool(512, ngx_cycle->log); @@ -2063,6 +2064,14 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, #endif /* LUA_HAVE_PCRE_JIT */ + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + + if (sd && lmcf && lmcf->regex_match_limit > 0) { + sd->flags |= PCRE_EXTRA_MATCH_LIMIT; + sd->match_limit = lmcf->regex_match_limit; + } + if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; From 6227668ef060d9ae49ac0ce1165f3e18915cc018 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 31 Aug 2013 19:09:33 -0700 Subject: [PATCH 0201/1981] bugfix: the FFI version of the PCRE API did not generate debug logs indicating the result of PCRE JIT compilation. --- src/ngx_http_lua_regex.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 84943e9e38..c134fa88b0 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2056,6 +2056,27 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); +# if (NGX_DEBUG) + if (msg != NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); + } + + if (sd != NULL) { + int jitted; + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); + + ngx_http_lua_pcre_malloc_done(old_pool); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "pcre JIT compiling result: %d", jitted); + } +# endif /* !(NGX_DEBUG) */ + } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, 0, &msg); From d9400dc435c8bfec8c7b0fab73a0ae16f15445d5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 31 Aug 2013 19:19:52 -0700 Subject: [PATCH 0202/1981] skipped the regex tests for checking bad data types, which cannot pass with lua-resty-core. --- t/036-sub.t | 2 ++ t/039-sub-o.t | 2 ++ 2 files changed, 4 insertions(+) diff --git a/t/036-sub.t b/t/036-sub.t index 0e59a92cc3..3e38cb07e5 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -323,6 +323,7 @@ hello, 34 false bad argument #3 to '?' (string, number, or function expected, got boolean) nil +--- SKIP @@ -346,6 +347,7 @@ hello, 724 === TEST 18: bad function return value type +--- SKIP --- config location /re { content_by_lua ' diff --git a/t/039-sub-o.t b/t/039-sub-o.t index c08987fc53..7ed05eb791 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -312,6 +312,7 @@ hello, 34 === TEST 16: bad repl arg type +--- SKIP --- config location /re { content_by_lua ' @@ -350,6 +351,7 @@ hello, 724 === TEST 18: bad function return value type +--- SKIP --- config location /re { content_by_lua ' From b68729345b1b9bbc9342a0d6943fc1fff996aa85 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 1 Sep 2013 00:10:24 -0700 Subject: [PATCH 0203/1981] bugfix: the FFI C API function ngx_http_lua_ffi_compile_regex could leak memory when pcre failed to compile the regex pattern argument. --- src/ngx_http_lua_regex.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index c134fa88b0..19ccb6fd61 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2045,7 +2045,8 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, if (rc != NGX_OK) { re_comp.err.data[re_comp.err.len] = '\0'; - return NULL; + msg = (char *) re_comp.err.data; + goto error; } #if (LUA_HAVE_PCRE_JIT) From e7f3b026453aee65b93970e8584f9908cca7dc5c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 1 Sep 2013 00:41:50 -0700 Subject: [PATCH 0204/1981] feature: added new FFI C API for shdict:get(). also we use double instead of lua_Number when storing Lua numbers into shdict. --- src/ngx_http_lua_shdict.c | 155 +++++++++++++++++++++++++++++++++++--- t/043-shdict.t | 5 +- 2 files changed, 148 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 7e2f04aa77..31de85b11a 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -384,7 +384,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; - lua_Number num; + double num; u_char c; ngx_shm_zone_t *zone; uint32_t user_flags = 0; @@ -463,7 +463,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) case LUA_TNUMBER: - if (value.len != sizeof(lua_Number)) { + if (value.len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -472,7 +472,7 @@ ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) (unsigned long) value.len); } - num = *(lua_Number *) value.data; + num = *(double *) value.data; lua_pushnumber(L, num); break; @@ -813,7 +813,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; - lua_Number num; + double num; u_char c; lua_Number exptime = 0; u_char *p; @@ -864,7 +864,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) break; case LUA_TNUMBER: - value.len = sizeof(lua_Number); + value.len = sizeof(double); num = lua_tonumber(L, 3); value.data = (u_char *) # break; @@ -1120,10 +1120,10 @@ ngx_http_lua_shdict_incr(lua_State *L) ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; - lua_Number num; + double num; u_char *p; ngx_shm_zone_t *zone; - lua_Number value; + double value; n = lua_gettop(L); @@ -1178,7 +1178,7 @@ ngx_http_lua_shdict_incr(lua_State *L) /* rc == NGX_OK */ - if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(lua_Number)) { + if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); @@ -1193,10 +1193,10 @@ ngx_http_lua_shdict_incr(lua_State *L) p = sd->data + key.len; - num = *(lua_Number *) p; + num = *(double *) p; num += value; - ngx_memcpy(p, (lua_Number *) &num, sizeof(lua_Number)); + ngx_memcpy(p, (double *) &num, sizeof(double)); ngx_shmtx_unlock(&ctx->shpool->mutex); @@ -1267,7 +1267,7 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, case LUA_TNUMBER: - if (len != sizeof(lua_Number)) { + if (len != sizeof(double)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number " "value size found for key %*s: %lu", key_len, key_data, (unsigned long) len); @@ -1345,4 +1345,137 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) return NULL; } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +int +ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, int *value_type, u_char **str_value_buf, + size_t *str_value_len, double *num_value, int *user_flags, + int get_stale, int *is_stale) +{ + ngx_str_t name; + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + ngx_str_t value; + + if (zone == NULL) { + return NGX_ERROR; + } + + ctx = zone->data; + name = ctx->name; + + hash = ngx_crc32_short(key, key_len); + +#if (NGX_DEBUG) + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "fetching key \"%*s\" in shared dict \"%V\"", key_len, + key, &name); +#endif /* NGX_DEBUG */ + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + if (!get_stale) { + ngx_http_lua_shdict_expire(ctx, 1); + } +#endif + + rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); + + dd("shdict lookup returns %d", (int) rc); + + if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *value_type = LUA_TNIL; + return NGX_OK; + } + + /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ + + *value_type = sd->value_type; + + dd("data: %p", sd->data); + dd("key len: %d", (int) sd->key_len); + + value.data = sd->data + sd->key_len; + value.len = (size_t) sd->value_len; + + if (*str_value_len < (size_t) value.len) { + if (*value_type != LUA_TSTRING) { + return NGX_ERROR; + } + + *str_value_buf = malloc(value.len); + if (*str_value_buf == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + } + + *str_value_len = value.len; + + switch (*value_type) { + case LUA_TSTRING: + ngx_memcpy(*str_value_buf, value.data, value.len); + break; + + case LUA_TNUMBER: + + if (value.len != sizeof(double)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad lua number value size found for key %*s " + "in shared_dict %V: %z", key_len, key, + &name, value.len); + return NGX_ERROR; + } + + *num_value = *(double *) value.data; + break; + + case LUA_TBOOLEAN: + + if (value.len != sizeof(u_char)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad lua boolean value size found for key %*s " + "in shared_dict %V: %z", key_len, key, &name, + value.len); + return NGX_ERROR; + } + + ngx_memcpy(*str_value_buf, value.data, value.len); + break; + + default: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad value type found for key %*s in " + "shared_dict %V: %d", key_len, key, &name, + *value_type); + } + + *user_flags = sd->user_flags; + dd("user flags: %d", *user_flags); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + if (get_stale) { + + /* always return value, flags, stale */ + + *is_stale = (rc == NGX_DONE); + return NGX_OK; + } + + return NGX_OK; +} + + +#endif /* NGX_HTTP_LUA_NO_FFI_API */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/043-shdict.t b/t/043-shdict.t index 3b46dea15a..eda0b218a3 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -8,7 +8,7 @@ use t::TestNginxLua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 15); +plan tests => repeat_each() * (blocks() * 2 + 16); #no_diff(); no_long_string(); @@ -114,6 +114,8 @@ truenilfalse dog dog bird string +--- no_error_log +[error] @@ -334,6 +336,7 @@ nil === TEST 13: not feed the object into the call +--- SKIP --- http_config lua_shared_dict dogs 1m; --- config From 6473e2242aa93798556f820283d6ddc38e3af072 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 1 Sep 2013 00:43:55 -0700 Subject: [PATCH 0205/1981] minor coding style fixes. --- src/ngx_http_lua_regex.c | 6 +++--- src/ngx_http_lua_string.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 19ccb6fd61..1bc19d22de 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2002,8 +2002,8 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, #ifndef NGX_HTTP_LUA_NO_FFI_API ngx_http_lua_regex_t * ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, - int flags, int pcre_opts, u_char *errstr, - size_t errstr_size) + int flags, int pcre_opts, u_char *errstr, + size_t errstr_size) { int *cap = NULL, ovecsize; u_char *p; @@ -2292,7 +2292,7 @@ ngx_http_lua_ffi_destroy_script_engine(ngx_http_lua_script_engine_t *e) size_t ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, - ngx_http_lua_complex_value_t *val) + ngx_http_lua_complex_value_t *val) { size_t len; diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index bc97c54947..55eb08fbb9 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -631,7 +631,7 @@ ngx_http_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst) int ngx_http_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst, - size_t *dlen) + size_t *dlen) { ngx_int_t rc; ngx_str_t in, out; From b6d19752e3ea279a57378f77940dfa4ce1b26089 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 1 Sep 2013 19:57:24 -0700 Subject: [PATCH 0206/1981] feature: added new FFI C API ngx_http_lua_ffi_shdict_incr for shdict:incr(). --- src/ngx_http_lua_shdict.c | 58 +++++++++++++++++++++++++++++++++++++++ t/043-shdict.t | 4 ++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 31de85b11a..840315573e 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1476,6 +1476,64 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, } +int +ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, double *value, char **err) +{ + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + double num; + u_char *p; + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, + (int) ctx->name.len, ctx->name.data); + + ngx_shmtx_lock(&ctx->shpool->mutex); +#if 1 + ngx_http_lua_shdict_expire(ctx, 1); +#endif + rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *err = "not found"; + return NGX_ERROR; + } + + /* rc == NGX_OK */ + + if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *err = "not a number"; + return NGX_ERROR; + } + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); + + dd("setting value type to %d", (int) sd->value_type); + + p = sd->data + key_len; + + num = *(double *) p; + num += *value; + + ngx_memcpy(p, (double *) &num, sizeof(double)); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *value = num; + return NGX_OK; +} + + #endif /* NGX_HTTP_LUA_NO_FFI_API */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/043-shdict.t b/t/043-shdict.t index eda0b218a3..deca88cf1d 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -8,7 +8,7 @@ use t::TestNginxLua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 16); +plan tests => repeat_each() * (blocks() * 2 + 17); #no_diff(); no_long_string(); @@ -893,6 +893,8 @@ GET /test --- response_body incr: nil not found foo = nil +--- no_error_log +[error] From db7a8c90c16e1a1b42d0a9bf9c4e0a337629cfae Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 1 Sep 2013 22:44:00 -0700 Subject: [PATCH 0207/1981] feature: added new FFI C API function ngx_http_lua_ffi_var_get for reading ngx.var.VARIABLE. --- src/ngx_http_lua_variable.c | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index ebaf56f9bd..8775fe0765 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -277,4 +277,80 @@ ngx_http_lua_var_set(lua_State *L) lowcase, lowcase); } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +int +ngx_http_lua_ffi_var_get(ngx_http_request_t *r, u_char *name_data, + size_t name_len, u_char *lowcase_buf, int capture_id, u_char **value, + size_t *value_len, char **err) +{ + u_char *p; + ngx_uint_t hash; + ngx_str_t name; + ngx_http_variable_value_t *vv; + +#if (NGX_PCRE) + ngx_uint_t n; + int *cap; +#endif + + if (r == NULL) { + *err = "no request object found"; + return NGX_ERROR; + } + + if ((r)->connection->fd == -1) { + *err = "API disabled in the current context"; + return NGX_ERROR; + } + +#if (NGX_PCRE) + if (name_data == 0) { + if (capture_id <= 0) { + return NGX_DECLINED; + } + + /* it is a regex capturing variable */ + + n = (ngx_uint_t) capture_id * 2; + + dd("n = %d, ncaptures = %d", (int) n, (int) r->ncaptures); + + if (r->captures == NULL + || r->captures_data == NULL + || n >= r->ncaptures) + { + return NGX_DECLINED; + } + + /* n >= 0 && n < r->ncaptures */ + + cap = r->captures; + p = r->captures_data; + + *value = &p[cap[n]]; + *value_len = (size_t) (cap[n + 1] - cap[n]); + + return NGX_OK; + } +#endif + + hash = ngx_hash_strlow(lowcase_buf, name_data, name_len); + + name.data = lowcase_buf; + name.len = name_len; + + dd("variable name: %.*s", (int) name_len, lowcase_buf); + + vv = ngx_http_get_variable(r, &name, hash); + if (vv == NULL || vv->not_found) { + return NGX_DECLINED; + } + + *value = vv->data; + *value_len = vv->len; + return NGX_OK; +} +#endif /* NGX_HTTP_LUA_NO_FFI_API */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 138bc9d91266a7c5636da743edda4c9c58579c68 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 2 Sep 2013 12:58:33 -0700 Subject: [PATCH 0208/1981] documented the new ngx.config.debug API and also updated docs to reflect other recent changes. --- README | 28 +++++++++++++++++++++------- README.markdown | 21 ++++++++++++++++----- doc/HttpLuaModule.wiki | 20 +++++++++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/README b/README index ee4ced47d8..e7eb845777 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.6 - () released on 6 - August 2013. + This document describes ngx_lua v0.8.7 + () released on 2 + September 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -5450,6 +5450,18 @@ Nginx API for Lua This API was first introduced in the "v0.8.0" release. + ngx.config.debug + syntax: *debug = ngx.config.debug* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, + init_by_lua** + + This boolean field indicates whether the current Nginx is a debug build, + i.e., being built by the "./configure" option "--with-debug". + + This field was first introduced in the 0.8.7. + ndk.set_var.DIRECTIVE syntax: *res = ndk.set_var.DIRECTIVE_NAME* @@ -5926,7 +5938,9 @@ Typical Uses Nginx Compatibility The latest module is compatible with the following versions of Nginx: - * 1.4.x (last tested: 1.4.1) + * 1.5.x (last tested: 1.5.4) + + * 1.4.x (last tested: 1.4.2) * 1.3.x (last tested: 1.3.11) @@ -5971,9 +5985,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' - tar -xzvf nginx-1.4.1.tar.gz - cd nginx-1.4.1/ + wget 'http://nginx.org/download/nginx-1.4.2.tar.gz' + tar -xzvf nginx-1.4.2.tar.gz + cd nginx-1.4.2/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/README.markdown b/README.markdown index cbb12efa62..048066dc2e 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 6 August 2013. +This document describes ngx_lua [v0.8.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 2 September 2013. Synopsis ======== @@ -4878,6 +4878,16 @@ this context. This API was first introduced in the `v0.8.0` release. +ngx.config.debug +---------------- +**syntax:** *debug = ngx.config.debug* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** + +This boolean field indicates whether the current Nginx is a debug build, i.e., being built by the `./configure` option `--with-debug`. + +This field was first introduced in the `0.8.7`. + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* @@ -5261,7 +5271,8 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.4.x (last tested: 1.4.1) +* 1.5.x (last tested: 1.5.4) +* 1.4.x (last tested: 1.4.2) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) @@ -5289,9 +5300,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' - tar -xzvf nginx-1.4.1.tar.gz - cd nginx-1.4.1/ + wget 'http://nginx.org/download/nginx-1.4.2.tar.gz' + tar -xzvf nginx-1.4.2.tar.gz + cd nginx-1.4.2/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 6fb4ce21e3..9f5d3311b7 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.6] released on 6 August 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.7] released on 2 September 2013. = Synopsis = @@ -4721,6 +4721,15 @@ this context. This API was first introduced in the v0.8.0 release. +== ngx.config.debug == +'''syntax:''' ''debug = ngx.config.debug'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*'' + +This boolean field indicates whether the current Nginx is a debug build, i.e., being built by the ./configure option --with-debug. + +This field was first introduced in the 0.8.7. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' @@ -5086,7 +5095,8 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.4.x (last tested: 1.4.1) +* 1.5.x (last tested: 1.5.4) +* 1.4.x (last tested: 1.4.2) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) * 1.1.x (last tested: 1.1.5) @@ -5112,9 +5122,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.4.1.tar.gz' - tar -xzvf nginx-1.4.1.tar.gz - cd nginx-1.4.1/ + wget 'http://nginx.org/download/nginx-1.4.2.tar.gz' + tar -xzvf nginx-1.4.2.tar.gz + cd nginx-1.4.2/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From 539a3021fee028bdf25fb9979d120316910a4c59 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 3 Sep 2013 17:08:20 -0700 Subject: [PATCH 0209/1981] one minor optimization in ngx.req.socket(). --- src/ngx_http_lua_socket_tcp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 6258de9f31..66bfac1d87 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3146,8 +3146,7 @@ ngx_http_lua_req_socket(lua_State *L) } lua_settop(L, 1); - lua_pushnil(L); - return 2; + return 1; } From 4ed6e7a54bf960f9993c30bfe0176c2ebda664e9 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 4 Sep 2013 11:51:16 -0700 Subject: [PATCH 0210/1981] bugfix: ngx.flush(true) might hang when there was a buggy output body filter. now we only test the condition "r->connection->buffered & NGX_LOWLEVEL_BUFFERED". --- src/ngx_http_lua_output.c | 2 +- src/ngx_http_lua_util.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 8be60a258b..61c2f07cbe 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -558,7 +558,7 @@ ngx_http_lua_ngx_flush(lua_State *L) dd("wait:%d, rc:%d, buffered:%d", wait, (int) rc, r->connection->buffered); - if (wait && r->connection->buffered) { + if (wait && (r->connection->buffered & NGX_LOWLEVEL_BUFFERED)) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua flush requires waiting: buffered 0x%uxd", (int) r->connection->buffered); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 81c671bcf9..77a2b20841 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1563,7 +1563,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto useless; } - if (c->buffered) { + if (c->buffered & NGX_LOWLEVEL_BUFFERED) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua wev handler flushing output: buffered 0x%uxd", c->buffered); @@ -1595,7 +1595,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) &ngx_http_lua_module, (int) c->buffered, ctx->busy_bufs); } - if (c->buffered) { + if (c->buffered & NGX_LOWLEVEL_BUFFERED) { if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); From 29a253b55808da5e8d5b681c1a3bdbfa3eca725f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 4 Sep 2013 12:13:35 -0700 Subject: [PATCH 0211/1981] Revert "bugfix: ngx.flush(true) might hang when there was a buggy output body filter. now we only test the condition "r->connection->buffered & NGX_LOWLEVEL_BUFFERED"." This reverts commit 4ed6e7a54bf960f9993c30bfe0176c2ebda664e9. --- src/ngx_http_lua_output.c | 2 +- src/ngx_http_lua_util.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 61c2f07cbe..8be60a258b 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -558,7 +558,7 @@ ngx_http_lua_ngx_flush(lua_State *L) dd("wait:%d, rc:%d, buffered:%d", wait, (int) rc, r->connection->buffered); - if (wait && (r->connection->buffered & NGX_LOWLEVEL_BUFFERED)) { + if (wait && r->connection->buffered) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua flush requires waiting: buffered 0x%uxd", (int) r->connection->buffered); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 77a2b20841..81c671bcf9 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1563,7 +1563,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto useless; } - if (c->buffered & NGX_LOWLEVEL_BUFFERED) { + if (c->buffered) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua wev handler flushing output: buffered 0x%uxd", c->buffered); @@ -1595,7 +1595,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) &ngx_http_lua_module, (int) c->buffered, ctx->busy_bufs); } - if (c->buffered & NGX_LOWLEVEL_BUFFERED) { + if (c->buffered) { if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); From 37a502108b916f40ba007fa88b4c3b1702ce59ed Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 4 Sep 2013 12:19:47 -0700 Subject: [PATCH 0212/1981] minor code refactoring to make the ngx_http_lua_wev_handler function shorter. --- src/ngx_http_lua_util.c | 144 ++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 59 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 81c671bcf9..30626dd22a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -96,6 +96,8 @@ static void ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_on_abort_resume(ngx_http_request_t *r); static void ngx_http_lua_close_fake_request(ngx_http_request_t *r); static void ngx_http_lua_free_fake_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_lua_flush_pending_output(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx); #ifndef LUA_PATH_SEP @@ -1513,7 +1515,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_connection_t *c; ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; - ngx_chain_t *cl; ngx_http_lua_co_ctx_t *coctx; ngx_uint_t i; @@ -1564,66 +1565,10 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } if (c->buffered) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua wev handler flushing output: buffered 0x%uxd", - c->buffered); - - rc = ngx_http_lua_output_filter(r, NULL); - - if (rc == NGX_ERROR || rc > NGX_OK) { - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, rc); - } - + rc = ngx_http_lua_flush_pending_output(r, ctx); + if (rc != NGX_OK) { return rc; } - - if (ctx->busy_bufs) { - cl = NULL; - - dd("updating chains..."); - -#if nginx_version >= 1001004 - ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif - &ctx->free_bufs, &ctx->busy_bufs, &cl, - (ngx_buf_tag_t) &ngx_http_lua_module); - - dd("update lua buf tag: %p, buffered: %x, busy bufs: %p", - &ngx_http_lua_module, (int) c->buffered, ctx->busy_bufs); - } - - if (c->buffered) { - - if (!wev->delayed) { - ngx_add_timer(wev, clcf->send_timeout); - } - - if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { - if (ctx->entered_content_phase) { - ngx_http_lua_finalize_request(r, NGX_ERROR); - } - - return NGX_ERROR; - } - - if (ctx->flushing_coros) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua flush still waiting: buffered 0x%uxd", - c->buffered); - - return NGX_DONE; - } - - } else { -#if 1 - if (wev->timer_set) { - ngx_del_timer(wev); - } -#endif - } } if (ctx->flushing_coros) { @@ -1704,6 +1649,87 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_lua_flush_pending_output(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_connection_t *c; + + ngx_http_core_loc_conf_t *clcf; + + c = r->connection; + wev = c->write; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua flushing output: buffered 0x%uxd", + c->buffered); + + rc = ngx_http_lua_output_filter(r, NULL); + + if (rc == NGX_ERROR || rc > NGX_OK) { + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, rc); + } + + return rc; + } + + if (ctx->busy_bufs) { + cl = NULL; + + dd("updating chains..."); + +#if nginx_version >= 1001004 + ngx_chain_update_chains(r->pool, +#else + ngx_chain_update_chains( +#endif + &ctx->free_bufs, &ctx->busy_bufs, &cl, + (ngx_buf_tag_t) &ngx_http_lua_module); + + dd("update lua buf tag: %p, buffered: %x, busy bufs: %p", + &ngx_http_lua_module, (int) c->buffered, ctx->busy_bufs); + } + + if (c->buffered) { + + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); + + if (!wev->delayed) { + ngx_add_timer(wev, clcf->send_timeout); + } + + if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { + if (ctx->entered_content_phase) { + ngx_http_lua_finalize_request(r, NGX_ERROR); + } + + return NGX_ERROR; + } + + if (ctx->flushing_coros) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua flush still waiting: buffered 0x%uxd", + c->buffered); + + return NGX_DONE; + } + + } else { +#if 1 + if (wev->timer_set) { + ngx_del_timer(wev); + } +#endif + } + + return NGX_OK; +} + + u_char * ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, int buf_len) { From 9d5bb2aa5856d9f646092a36483c976252c18e02 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 4 Sep 2013 12:31:23 -0700 Subject: [PATCH 0213/1981] refactor: made the "processing flushing coroutines" process a separate C function. --- src/ngx_http_lua_util.c | 116 ++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 52 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 30626dd22a..27e92b9a20 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -98,6 +98,9 @@ static void ngx_http_lua_close_fake_request(ngx_http_request_t *r); static void ngx_http_lua_free_fake_request(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_flush_pending_output(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); +static ngx_int_t + ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx); #ifndef LUA_PATH_SEP @@ -1510,13 +1513,10 @@ ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r) { ngx_int_t rc; - ngx_list_part_t *part; ngx_http_lua_ctx_t *ctx; ngx_connection_t *c; ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; - ngx_http_lua_co_ctx_t *coctx; - ngx_uint_t i; c = r->connection; @@ -1572,77 +1572,89 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } if (ctx->flushing_coros) { + return ngx_http_lua_process_flushing_coroutines(r, ctx); + } - coctx = &ctx->entry_co_ctx; + /* ctx->flushing_coros == 0 */ - if (coctx->flushing) { - coctx->flushing = 0; +useless: + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "useless lua write event handler"); - ctx->flushing_coros--; - ctx->cur_co_ctx = coctx; + if (ctx->entered_content_phase) { + return NGX_OK; + } - rc = ngx_http_lua_flush_resume_helper(r, ctx); - if (rc == NGX_ERROR || rc >= NGX_OK) { - return rc; - } + return NGX_DONE; +} - /* rc == NGX_DONE */ - } - if (ctx->flushing_coros) { +static ngx_int_t +ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_http_lua_co_ctx_t *coctx; - if (ctx->user_co_ctx == NULL) { - return NGX_ERROR; - } + coctx = &ctx->entry_co_ctx; - part = &ctx->user_co_ctx->part; - coctx = part->elts; + if (coctx->flushing) { + coctx->flushing = 0; - for (i = 0; /* void */; i++) { + ctx->flushing_coros--; + ctx->cur_co_ctx = coctx; - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } + rc = ngx_http_lua_flush_resume_helper(r, ctx); + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } - part = part->next; - coctx = part->elts; - i = 0; - } + /* rc == NGX_DONE */ + } - if (coctx[i].flushing) { - coctx[i].flushing = 0; - ctx->cur_co_ctx = &coctx[i]; + if (ctx->flushing_coros) { - rc = ngx_http_lua_flush_resume_helper(r, ctx); - if (rc == NGX_ERROR || rc >= NGX_OK) { - return rc; - } + if (ctx->user_co_ctx == NULL) { + return NGX_ERROR; + } - /* rc == NGX_DONE */ + part = &ctx->user_co_ctx->part; + coctx = part->elts; - if (--ctx->flushing_coros == 0) { - break; - } + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; } + + part = part->next; + coctx = part->elts; + i = 0; } - } - if (ctx->flushing_coros) { - return NGX_ERROR; - } + if (coctx[i].flushing) { + coctx[i].flushing = 0; + ctx->cur_co_ctx = &coctx[i]; - return NGX_DONE; - } + rc = ngx_http_lua_flush_resume_helper(r, ctx); + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } - /* ctx->flushing_coros == 0 */ + /* rc == NGX_DONE */ -useless: - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "useless lua write event handler"); + if (--ctx->flushing_coros == 0) { + break; + } + } + } + } - if (ctx->entered_content_phase) { - return NGX_OK; + if (ctx->flushing_coros) { + return NGX_ERROR; } return NGX_DONE; From 45f430a006dc38896b37cc18d502a09c53aa4e4f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 4 Sep 2013 16:43:42 -0700 Subject: [PATCH 0214/1981] feature: added new option "always_forward_body" to ngx.location.capture(), which controls whether to always forward the parent request's request body to the subrequest. --- src/ngx_http_lua_subrequest.c | 24 +++++++--- t/020-subrequest.t | 86 +++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 0c2a71e4bc..fb8d483598 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -58,7 +58,8 @@ static ngx_str_t ngx_http_lua_content_length_header_key = static ngx_int_t ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len); static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, - ngx_uint_t method, ngx_http_request_body_t *body, unsigned vars_action, + ngx_uint_t method, int forward_body, + ngx_http_request_body_t *body, unsigned vars_action, ngx_array_t *extra_vars); static int ngx_http_lua_ngx_location_capture(lua_State *L); static int ngx_http_lua_ngx_location_capture_multi(lua_State *L); @@ -127,6 +128,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) size_t nargs; int rc; int n; + int always_forward_body = 0; ngx_uint_t method; ngx_http_request_body_t *body; int type; @@ -364,6 +366,14 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) dd("queries query uri opts: %d", lua_gettop(L)); + /* check the "forward_body" option */ + + lua_getfield(L, 4, "always_forward_body"); + always_forward_body = lua_toboolean(L, -1); + lua_pop(L, 1); + + dd("always foward body: %d", always_forward_body); + /* check the "method" option */ lua_getfield(L, 4, "method"); @@ -561,8 +571,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); - rc = ngx_http_lua_adjust_subrequest(sr, method, body, vars_action, - extra_vars); + rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, + body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); @@ -597,8 +607,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, - ngx_http_request_body_t *body, unsigned vars_action, - ngx_array_t *extra_vars) + int always_forward_body, ngx_http_request_body_t *body, + unsigned vars_action, ngx_array_t *extra_vars) { ngx_http_request_t *r; ngx_int_t rc; @@ -621,7 +631,9 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, return NGX_ERROR; } - } else if (method != NGX_HTTP_PUT && method != NGX_HTTP_POST + } else if (!always_forward_body + && method != NGX_HTTP_PUT + && method != NGX_HTTP_POST && r->headers_in.content_length_n > 0) { rc = ngx_http_lua_set_content_length_header(sr, 0); diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 565d181ef2..cd7ff98fd5 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -2304,3 +2304,89 @@ 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 +--- response_body +hello world +--- no_error_log +[error] + From 75d2524ba50b247937d1aa5c334c6364ea273378 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 5 Sep 2013 14:55:32 -0700 Subject: [PATCH 0215/1981] added a (passing) test for recalling the connect() method on the same tcp cosocket object right after a connecting timed out error happens. --- t/065-tcp-socket-timeout.t | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 22326ae369..17b4bad1e2 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -673,3 +673,40 @@ after --- no_error_log [error] + + +=== TEST 17: re-connect after timed out +--- config + server_tokens off; + lua_socket_connect_timeout 100ms; + resolver $TEST_NGINX_RESOLVER; + resolver_timeout 1s; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("agentzh.org", 12345) + if not ok then + ngx.say("1: failed to connect: ", err) + + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("2: failed to connect: ", err) + return + end + + ngx.say("2: connected: ", ok) + return + end + + ngx.say("1: connected: ", ok) + '; + } +--- request +GET /t +--- response_body +1: failed to connect: timeout +2: connected: 1 +--- error_log +lua tcp socket connect timeout: 100 +lua tcp socket connect timed out + From 438bbca78e5848f523efcde807247540129dd93a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 5 Sep 2013 14:59:03 -0700 Subject: [PATCH 0216/1981] added a (passing) test for recalling the send() method on the same tcp cosocket object right after a send timeout error happens. --- t/065-tcp-socket-timeout.t | 58 +++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 17b4bad1e2..5b054ce2d8 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -24,7 +24,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 10); +plan tests => repeat_each() * (blocks() * 4 + 11); our $HtmlDir = html_dir; @@ -710,3 +710,59 @@ GET /t lua tcp socket connect timeout: 100 lua tcp socket connect timed out + + +=== TEST 18: re-send on the same object after a send timeout happens +--- config + server_tokens off; + lua_socket_send_timeout 100ms; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local bytes + bytes, err = sock:send("get helloworld!") + if bytes then + ngx.say("sent: ", bytes) + else + ngx.say("failed to send: ", err) + bytes, err = sock:send("blah") + if not bytes then + ngx.say("failed to send again: ", err) + end + end + '; + } +--- request +GET /t +--- stap2 +global active = 0 +F(ngx_http_lua_socket_send) { + active = 1 + println(probefunc()) +} +probe syscall.send, + syscall.sendto, + syscall.writev +{ + if (active && pid() == target()) { + println(probefunc()) + } +} +--- response_body +connected: 1 +failed to send: timeout +failed to send again: closed +--- error_log +lua tcp socket send timeout: 100 +lua tcp socket connect timeout: 60000 +lua tcp socket write timed out + From 1a9f044dc12c37b8778a201c21f4781f0118b005 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 5 Sep 2013 15:54:34 -0700 Subject: [PATCH 0217/1981] now we allow application of the mockeagain reading mode to the test files that require the mockegain writing mode. --- t/023-rewrite/tcp-socket-timeout.t | 7 ++++++- t/057-flush-timeout.t | 7 ++++++- t/065-tcp-socket-timeout.t | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index f10189b318..aa6d46b5e1 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -9,7 +9,12 @@ BEGIN { $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; } - $ENV{MOCKEAGAIN} = 'w'; + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index d09c36bc73..4debe71067 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -9,7 +9,12 @@ BEGIN { $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; } - $ENV{MOCKEAGAIN} = 'w'; + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'hello, world'; diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 5b054ce2d8..b79d4bf192 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -9,7 +9,12 @@ BEGIN { $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; } - $ENV{MOCKEAGAIN} = 'w'; + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'get helloworld'; From 2926596a291d24eefb62b8f089457a127cf59286 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 5 Sep 2013 17:32:04 -0700 Subject: [PATCH 0218/1981] feature: now timeout errors in tcpsock:receive() and the reader returned by tcpsock:receiveuntil() no longer close the current cosocket object automatically. thanks Aviram Cohen for the original patch. --- src/ngx_http_lua_socket_tcp.c | 29 ++- src/ngx_http_lua_socket_tcp.h | 1 + t/058-tcp-socket.t | 364 +++++++++++++++++++++++++++++++++- t/067-req-socket.t | 313 +++++++++++++++++++++++++++++ 4 files changed, 699 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 66bfac1d87..27f133a999 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -916,6 +916,7 @@ static int ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L) { + ngx_uint_t ft_type; u_char errstr[NGX_MAX_ERROR_STR]; u_char *p; @@ -926,27 +927,35 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, u->co_ctx->cleanup = NULL; } - ngx_http_lua_socket_tcp_finalize(r, u); + ft_type = u->ft_type; - if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { + if (u->no_close) { + u->no_close = 0; + u->ft_type = 0; + + } else { + ngx_http_lua_socket_tcp_finalize(r, u); + } + + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { return 2; } lua_pushnil(L); - if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { + if (ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { lua_pushliteral(L, "timeout"); - } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_CLOSED) { + } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_CLOSED) { lua_pushliteral(L, "closed"); - } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_BUFTOOSMALL) { + } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_BUFTOOSMALL) { lua_pushliteral(L, "buffer too small"); - } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_NOMEM) { + } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_NOMEM) { lua_pushliteral(L, "out of memory"); - } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT) { + } else if (ft_type & NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT) { lua_pushliteral(L, "client aborted"); } else { @@ -1810,6 +1819,10 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, if (u->ft_type) { + if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) { + u->no_close = 1; + } + dd("u->bufs_in: %p", u->bufs_in); if (u->bufs_in) { @@ -1991,6 +2004,8 @@ ngx_http_lua_socket_read_handler(ngx_http_request_t *r, "lua tcp socket read handler"); if (c->read->timedout) { + c->read->timedout = 0; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index 72fa00d3f4..e1a7688198 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -85,6 +85,7 @@ struct ngx_http_lua_socket_tcp_upstream_s { ngx_uint_t reused; + unsigned no_close:1; unsigned waiting:1; unsigned eof:1; unsigned is_downstream:1; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 5720852e55..fd7d84c5e3 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 99; +plan tests => repeat_each() * 120; our $HtmlDir = html_dir; @@ -2126,3 +2126,365 @@ close: nil closed --- no_error_log eval [qr/connect\(\) failed \(\d+: Connection refused\)/] + + +=== TEST 36: reread after a read time out happen (receive -> receive) +--- config + server_tokens off; + lua_socket_read_timeout 100ms; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local line + line, err = sock:receive() + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive: ", err) + + line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + end + end + '; + } +--- request +GET /t +--- response_body +connected: 1 +failed to receive: timeout +failed to receive: timeout +--- error_log +lua tcp socket read timeout: 100 +lua tcp socket connect timeout: 60000 +lua tcp socket read timed out + + + +=== TEST 37: successful reread after a read time out happen (receive -> receive) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("GET /back HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to read the response header: ", err) + return + end + + sock:settimeout(10) + + local data, err, partial = sock:receive(100) + if data then + ngx.say("received: ", data) + else + ngx.say("failed to receive: ", err, ", partial: ", partial) + + sock:settimeout(123) + ngx.sleep(0.1) + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location /back { + content_by_lua ' + ngx.print("hi") + ngx.flush(true) + ngx.sleep(0.1) + ngx.print("world") + '; + } +--- request +GET /t +--- response_body eval +"failed to receive: timeout, partial: 2\r +hi\r + +received: 5 +received: world +" +--- error_log +lua tcp socket read timed out +--- no_error_log +[alert] + + + +=== TEST 38: successful reread after a read time out happen (receive -> receiveuntil) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("GET /back HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to read the response header: ", err) + return + end + + sock:settimeout(10) + + local data, err, partial = sock:receive(100) + if data then + ngx.say("received: ", data) + else + ngx.say("failed to receive: ", err, ", partial: ", partial) + + ngx.sleep(0.1) + + sock:settimeout(123) + local reader = sock:receiveuntil("\\r\\n") + + local line, err = reader() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + + local line, err = reader() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location /back { + content_by_lua ' + ngx.print("hi") + ngx.flush(true) + ngx.sleep(0.1) + ngx.print("world") + '; + } +--- request +GET /t +--- response_body eval +"failed to receive: timeout, partial: 2\r +hi\r + +received: 5 +received: world +" +--- error_log +lua tcp socket read timed out +--- no_error_log +[alert] + + + +=== TEST 39: successful reread after a read time out happen (receiveuntil -> receiveuntil) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("GET /back HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to read the response header: ", err) + return + end + + sock:settimeout(10) + + local reader = sock:receiveuntil("no-such-terminator") + local data, err, partial = reader() + if data then + ngx.say("received: ", data) + else + ngx.say("failed to receive: ", err, ", partial: ", partial) + + ngx.sleep(0.1) + + sock:settimeout(123) + + local reader = sock:receiveuntil("\\r\\n") + + local line, err = reader() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + + local line, err = reader() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location /back { + content_by_lua ' + ngx.print("hi") + ngx.flush(true) + ngx.sleep(0.1) + ngx.print("world") + '; + } +--- request +GET /t +--- response_body eval +"failed to receive: timeout, partial: 2\r +hi\r + +received: 5 +received: world +" +--- error_log +lua tcp socket read timed out +--- no_error_log +[alert] + + + +=== TEST 40: successful reread after a read time out happen (receiveuntil -> receive) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("GET /back HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to read the response header: ", err) + return + end + + sock:settimeout(10) + + local reader = sock:receiveuntil("no-such-terminator") + local data, err, partial = reader() + if data then + ngx.say("received: ", data) + else + ngx.say("failed to receive: ", err, ", partial: ", partial) + + ngx.sleep(0.1) + + sock:settimeout(123) + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location /back { + content_by_lua ' + ngx.print("hi") + ngx.flush(true) + ngx.sleep(0.1) + ngx.print("world") + '; + } +--- request +GET /t +--- response_body eval +"failed to receive: timeout, partial: 2\r +hi\r + +received: 5 +received: world +" +--- error_log +lua tcp socket read timed out +--- no_error_log +[alert] + diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 374a1a1611..98dd4eb1e8 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -752,3 +752,316 @@ failed to get socket: no body --- no_error_log [error] + + +=== TEST 13: failing reread after reading timeout happens +--- config + location = /t { + content_by_lua ' + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + sock:settimeout(10); + + local data, err, partial = sock:receive(4096) + if err then + ngx.say("err: ", err, ", partial: ", partial) + end + + local data, err, partial = sock:receive(4096) + if err then + ngx.say("err: ", err, ", partial: ", partial) + return + end + '; + } + +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Content-Length: 10245\r +\r +hello" +--- response_body +err: timeout, partial: hello +err: timeout, partial: + +--- error_log +lua tcp socket read timed out + + + +=== TEST 14: successful reread after reading timeout happens (receive -> receive) +--- config + location = /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("POST /back HTTP/1.0\\r\\nHost: localhost\\r\\nContent-Length: 1024\\r\\n\\r\\nabc") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + ngx.sleep(0.1) + + local bytes, err = sock:send("hello world") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to receive header: ", err) + return + end + + for i = 1, 2 do + local line, err = sock:receive() + if not line then + ngx.say("failed to receive line: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location = /back { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + sock:settimeout(20); + + local data, err, partial = sock:receive(4096) + if err then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + + ngx.sleep(0.1) + + local data, err, partial = sock:receive(11) + if err then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + '; + } + +--- request +GET /t +--- response_body +sent: 65 +sent: 11 +received: err: timeout, partial: abc +received: received: hello world + +--- error_log +lua tcp socket read timed out + + + +=== TEST 15: successful reread after reading timeout happens (receive -> receiveuntil) +--- config + location = /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("POST /back HTTP/1.0\\r\\nHost: localhost\\r\\nContent-Length: 1024\\r\\n\\r\\nabc") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + ngx.sleep(0.1) + + local bytes, err = sock:send("hello world\\n") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to receive header: ", err) + return + end + + for i = 1, 2 do + local line, err = sock:receive() + if not line then + ngx.say("failed to receive line: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location = /back { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + sock:settimeout(20); + + local data, err, partial = sock:receive(4096) + if err then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + + ngx.sleep(0.1) + + local reader = sock:receiveuntil("\\n") + local data, err, partial = reader() + if err then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + '; + } + +--- request +GET /t +--- response_body +sent: 65 +sent: 12 +received: err: timeout, partial: abc +received: received: hello world + +--- error_log +lua tcp socket read timed out + + + +=== TEST 16: successful reread after reading timeout happens (receiveuntil -> receive) +--- config + location = /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", ngx.var.server_port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, err = sock:send("POST /back HTTP/1.0\\r\\nHost: localhost\\r\\nContent-Length: 1024\\r\\n\\r\\nabc") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + ngx.sleep(0.1) + + local bytes, err = sock:send("hello world\\n") + if not bytes then + ngx.say("failed to send: ", err) + else + ngx.say("sent: ", bytes) + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local header, err = reader() + if not header then + ngx.say("failed to receive header: ", err) + return + end + + for i = 1, 2 do + local line, err = sock:receive() + if not line then + ngx.say("failed to receive line: ", err) + return + end + ngx.say("received: ", line) + end + '; + } + + location = /back { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + + local sock, err = ngx.req.socket() + + if not sock then + ngx.say("failed to get socket: ", err) + return nil + end + + sock:settimeout(20); + + local reader = sock:receiveuntil("no-such-terminator") + local data, err, partial = reader() + if not data then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + + ngx.sleep(0.1) + + local data, err, partial = sock:receive() + if err then + ngx.say("err: ", err, ", partial: ", partial) + else + ngx.say("received: ", data) + end + '; + } + +--- request +GET /t +--- response_body +sent: 65 +sent: 12 +received: err: timeout, partial: abc +received: received: hello world + +--- error_log +lua tcp socket read timed out + From 7c5e3548ae9f893fd54c2ceb07560b44e9373a8f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 6 Sep 2013 23:59:17 -0700 Subject: [PATCH 0219/1981] bugfix: Lua backtrace dumps upon uncaught Lua exceptions did not work with the standard Lua 5.1 interpreter when the backtrace was deeper than 22 levels. now we just dump the top 22 levels in the backtrace for simplicity. also optimized the Lua string concatenation operations when constructing the backtrace string. --- src/ngx_http_lua_util.c | 44 +++++--------- t/073-backtrace.t | 125 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 31 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 27e92b9a20..a01f55fa82 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -55,6 +55,11 @@ #endif +#ifndef NGX_HTTP_LUA_BACKTRACE_DEPTH +#define NGX_HTTP_LUA_BACKTRACE_DEPTH 22 +#endif + + char ngx_http_lua_code_cache_key; char ngx_http_lua_ctx_tables_key; char ngx_http_lua_regex_cache_key; @@ -110,12 +115,6 @@ static ngx_int_t #define AUX_MARK "\1" -enum { - LEVELS1 = 12, /* size of the first part of the stack */ - LEVELS2 = 10 /* size of the second part of the stack */ -}; - - static void ngx_http_lua_set_path(ngx_conf_t *cf, lua_State *L, int tab_idx, const char *fieldname, const char *path, const char *default_path) @@ -2742,8 +2741,7 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, ngx_http_lua_co_ctx_t *coctx) { int base; - int level = 0, count = 0; - int firstpart = 1; /* still before eventual `...' */ + int level, count = 0; lua_Debug ar; base = lua_gettop(L); @@ -2754,25 +2752,13 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, lua_pushfstring(L, "\ncoroutine %d:", count++); - while (lua_getstack(co, level++, &ar)) { - - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(co, level + LEVELS2, &ar)) { - level--; /* keep going */ + level = 0; - } else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - /* - * This only works with LuaJIT 2.x. - * Avoids O(n^2) behaviour. - */ - lua_getstack(co, -10, &ar); - level = ar.i_ci - LEVELS2; - } + while (lua_getstack(co, level++, &ar)) { - firstpart = 0; - continue; + if (level > NGX_HTTP_LUA_BACKTRACE_DEPTH) { + lua_pushliteral(L, "\n\t..."); + break; } lua_pushliteral(L, "\n\t"); @@ -2800,10 +2786,9 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, } } - lua_concat(L, lua_gettop(L) - base); - - level = 0; - firstpart = 1; + if (lua_gettop(L) - base >= 15) { + lua_concat(L, lua_gettop(L) - base); + } /* check if the coroutine has a parent coroutine*/ coctx = coctx->parent_co_ctx; @@ -2814,6 +2799,7 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, co = coctx->co; } + lua_concat(L, lua_gettop(L) - base); return 1; } diff --git a/t/073-backtrace.t b/t/073-backtrace.t index e05081fcd1..e5dd5ceb40 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -10,10 +10,10 @@ use t::TestNginxLua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * 10; +plan tests => repeat_each() * 51; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -66,3 +66,124 @@ stack traceback: :5: in function 'foo' :7: in function <[string "content_by_lua"]:1> + + +=== TEST 3: deep backtrace in a single coroutine (more than 15) +--- config eval +my $s = " + location /lua { + content_by_lua ' +"; +my $prev; +for my $i (1..18) { + if (!defined $prev) { + $s .= " + local function func$i() + return error([[blah]]) + end"; + } else { + $s .= " + local function func$i() + local v = func$prev() + return v + end"; + } + $prev = $i; +} +$s .= " + func$prev() + '; + } +"; +--- request +GET /lua +--- stap2 +probe process("$LIBLUA_PATH").function("lua_concat") { + println("lua concat") + //print_ubacktrace() +} +--- stap_out2 +--- ignore_response +--- error_log +: blah +: in function 'func1' +:7: in function 'func2' +:11: in function 'func3' +:15: in function 'func4' +:19: in function 'func5' +:23: in function 'func6' +:27: in function 'func7' +:31: in function 'func8' +:35: in function 'func9' +:39: in function 'func10' +:43: in function 'func11' +:47: in function 'func12' +:51: in function 'func13' +:55: in function 'func14' +:59: in function 'func15' +:63: in function 'func16' +:67: in function 'func17' +:71: in function 'func18' +:74: in function + + + +=== TEST 4: deep backtrace in a single coroutine (more than 22) +--- config eval +my $s = " + location /lua { + content_by_lua ' +"; +my $prev; +for my $i (1..23) { + if (!defined $prev) { + $s .= " + local function func$i() + return error([[blah]]) + end"; + } else { + $s .= " + local function func$i() + local v = func$prev() + return v + end"; + } + $prev = $i; +} +$s .= " + func$prev() + '; + } +"; +--- request +GET /lua +--- stap2 +probe process("$LIBLUA_PATH").function("lua_concat") { + println("lua concat") + //print_ubacktrace() +} +--- stap_out2 +--- ignore_response +--- error_log +: blah +: in function 'func1' +:7: in function 'func2' +:11: in function 'func3' +:15: in function 'func4' +:19: in function 'func5' +:23: in function 'func6' +:27: in function 'func7' +:31: in function 'func8' +:35: in function 'func9' +:39: in function 'func10' +:43: in function 'func11' +:47: in function 'func12' +:59: in function 'func15' +:63: in function 'func16' +:67: in function 'func17' +:71: in function 'func18' +:75: in function 'func19' +:79: in function 'func20' +:83: in function 'func21' +... + From fe3c318faecbb8f92206e8506b90d37f483a82b0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 00:13:15 -0700 Subject: [PATCH 0220/1981] change: we now limit the number of nested coroutines in the backtrace dump for uncaught Lua exceptions by 5. --- src/ngx_http_lua_util.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a01f55fa82..04d29532cb 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -55,8 +55,13 @@ #endif -#ifndef NGX_HTTP_LUA_BACKTRACE_DEPTH -#define NGX_HTTP_LUA_BACKTRACE_DEPTH 22 +#ifndef NGX_HTTP_LUA_BT_DEPTH +#define NGX_HTTP_LUA_BT_DEPTH 22 +#endif + + +#ifndef NGX_HTTP_LUA_BT_MAX_COROS +#define NGX_HTTP_LUA_BT_MAX_COROS 5 #endif @@ -2741,22 +2746,26 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, ngx_http_lua_co_ctx_t *coctx) { int base; - int level, count = 0; + int level, coid; lua_Debug ar; base = lua_gettop(L); - lua_pushliteral(L, "stack traceback:"); + coid = 0; while (co) { - lua_pushfstring(L, "\ncoroutine %d:", count++); + if (coid >= NGX_HTTP_LUA_BT_MAX_COROS) { + break; + } + + lua_pushfstring(L, "\ncoroutine %d:", coid++); level = 0; while (lua_getstack(co, level++, &ar)) { - if (level > NGX_HTTP_LUA_BACKTRACE_DEPTH) { + if (level > NGX_HTTP_LUA_BT_DEPTH) { lua_pushliteral(L, "\n\t..."); break; } From 6e4b5745a9b29dde4aba7a476510096425cf6daa Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 12:49:44 -0700 Subject: [PATCH 0221/1981] bugfix: the null character ('\0') was not escaped in ngx.quote_sql_str() according to the MySQL quoting rules. thanks Siddon Tang for the report. --- src/ngx_http_lua_string.c | 6 ++++++ t/115-quote-sql-str.t | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 t/115-quote-sql-str.t diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 2a7ec72592..ff646f56d1 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -224,6 +224,7 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) * is always 1 */ if ((*src & 0x80) == 0) { switch (*src) { + case '\0': case '\r': case '\n': case '\\': @@ -246,6 +247,11 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) while (size) { if ((*src & 0x80) == 0) { switch (*src) { + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + break; + case '\r': *dst++ = '\\'; *dst++ = 'r'; diff --git a/t/115-quote-sql-str.t b/t/115-quote-sql-str.t new file mode 100644 index 0000000000..271a663586 --- /dev/null +++ b/t/115-quote-sql-str.t @@ -0,0 +1,30 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use t::TestNginxLua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#log_level("warn"); +no_long_string(); + +run_tests(); + +__DATA__ + +=== TEST 1: \0 +--- config + location = /set { + content_by_lua ' + ngx.say(ngx.quote_sql_str("a\\0b\\0")) + '; + } +--- request +GET /set +--- response_body +'a\0b\0' +--- no_error_log +[error] + From 0f7948d528bc9077872cd31f5ddf24ef584b54ef Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 13:25:21 -0700 Subject: [PATCH 0222/1981] bugfix: we did not escape \z, \t, and \b properly in ngx.quote_sql_str(). --- src/ngx_http_lua_string.c | 30 ++++++++++++++++-------- t/115-quote-sql-str.t | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index ff646f56d1..0922272a54 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -225,12 +225,14 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) if ((*src & 0x80) == 0) { switch (*src) { case '\0': - case '\r': + case '\b': case '\n': + case '\r': + case '\t': + case 26: /* \z */ case '\\': case '\'': case '"': - case '\032': n++; break; default: @@ -252,9 +254,9 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) *dst++ = '0'; break; - case '\r': + case '\b': *dst++ = '\\'; - *dst++ = 'r'; + *dst++ = 'b'; break; case '\n': @@ -262,6 +264,21 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) *dst++ = 'n'; break; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + break; + + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + break; + + case 26: + *dst++ = '\\'; + *dst++ = 'z'; + break; + case '\\': *dst++ = '\\'; *dst++ = '\\'; @@ -277,11 +294,6 @@ ngx_http_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) *dst++ = '"'; break; - case '\032': - *dst++ = '\\'; - *dst++ = *src; - break; - default: *dst++ = *src; break; diff --git a/t/115-quote-sql-str.t b/t/115-quote-sql-str.t index 271a663586..525a61b253 100644 --- a/t/115-quote-sql-str.t +++ b/t/115-quote-sql-str.t @@ -28,3 +28,51 @@ GET /set --- no_error_log [error] + + +=== TEST 2: \t +--- config + location = /set { + content_by_lua ' + ngx.say(ngx.quote_sql_str("a\\tb\\t")) + '; + } +--- request +GET /set +--- response_body +'a\tb\t' +--- no_error_log +[error] + + + +=== TEST 3: \b +--- config + location = /set { + content_by_lua ' + ngx.say(ngx.quote_sql_str("a\\bb\\b")) + '; + } +--- request +GET /set +--- response_body +'a\bb\b' +--- no_error_log +[error] + + + +=== TEST 4: \z +--- config + location = /set { + content_by_lua ' + ngx.say(ngx.quote_sql_str("a\\026b\\026")) + '; + } +--- request +GET /set +--- response_body +'a\zb\z' +--- no_error_log +[error] + From ba7c1766b7f8cbae33c5c00982ac8614f34f6d54 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 18:14:05 -0700 Subject: [PATCH 0223/1981] fixed those recently-added test cases that could fail in slow testing modes on slow machines. --- t/058-tcp-socket.t | 16 ++++++++-------- t/067-req-socket.t | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index fd7d84c5e3..01fef0ccc8 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -2197,7 +2197,7 @@ lua tcp socket read timed out return end - sock:settimeout(10) + sock:settimeout(100) local data, err, partial = sock:receive(100) if data then @@ -2228,7 +2228,7 @@ lua tcp socket read timed out content_by_lua ' ngx.print("hi") ngx.flush(true) - ngx.sleep(0.1) + ngx.sleep(0.2) ngx.print("world") '; } @@ -2274,7 +2274,7 @@ lua tcp socket read timed out return end - sock:settimeout(10) + sock:settimeout(100) local data, err, partial = sock:receive(100) if data then @@ -2308,7 +2308,7 @@ lua tcp socket read timed out content_by_lua ' ngx.print("hi") ngx.flush(true) - ngx.sleep(0.1) + ngx.sleep(0.2) ngx.print("world") '; } @@ -2354,7 +2354,7 @@ lua tcp socket read timed out return end - sock:settimeout(10) + sock:settimeout(100) local reader = sock:receiveuntil("no-such-terminator") local data, err, partial = reader() @@ -2390,7 +2390,7 @@ lua tcp socket read timed out content_by_lua ' ngx.print("hi") ngx.flush(true) - ngx.sleep(0.1) + ngx.sleep(0.2) ngx.print("world") '; } @@ -2436,7 +2436,7 @@ lua tcp socket read timed out return end - sock:settimeout(10) + sock:settimeout(100) local reader = sock:receiveuntil("no-such-terminator") local data, err, partial = reader() @@ -2470,7 +2470,7 @@ lua tcp socket read timed out content_by_lua ' ngx.print("hi") ngx.flush(true) - ngx.sleep(0.1) + ngx.sleep(0.2) ngx.print("world") '; } diff --git a/t/067-req-socket.t b/t/067-req-socket.t index 98dd4eb1e8..6651ecd81d 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -765,7 +765,7 @@ failed to get socket: no body return nil end - sock:settimeout(10); + sock:settimeout(100); local data, err, partial = sock:receive(4096) if err then @@ -813,7 +813,7 @@ lua tcp socket read timed out ngx.say("sent: ", bytes) end - ngx.sleep(0.1) + ngx.sleep(0.2) local bytes, err = sock:send("hello world") if not bytes then @@ -852,7 +852,7 @@ lua tcp socket read timed out return nil end - sock:settimeout(20); + sock:settimeout(100); local data, err, partial = sock:receive(4096) if err then @@ -903,7 +903,7 @@ lua tcp socket read timed out ngx.say("sent: ", bytes) end - ngx.sleep(0.1) + ngx.sleep(0.2) local bytes, err = sock:send("hello world\\n") if not bytes then @@ -942,7 +942,7 @@ lua tcp socket read timed out return nil end - sock:settimeout(20); + sock:settimeout(100); local data, err, partial = sock:receive(4096) if err then @@ -994,7 +994,7 @@ lua tcp socket read timed out ngx.say("sent: ", bytes) end - ngx.sleep(0.1) + ngx.sleep(0.2) local bytes, err = sock:send("hello world\\n") if not bytes then @@ -1033,7 +1033,7 @@ lua tcp socket read timed out return nil end - sock:settimeout(20); + sock:settimeout(100); local reader = sock:receiveuntil("no-such-terminator") local data, err, partial = reader() From 55776b7b5586ee06d2e6723760d0ef426ca23f05 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 22:44:21 -0700 Subject: [PATCH 0224/1981] tests: use larger timeout settings to account for slow DNS servers. --- t/058-tcp-socket.t | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 01fef0ccc8..217f3e4fbd 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -253,6 +253,7 @@ first line received: HTTP/1.1 200 OK second line received: Server: ngx_openresty --- no_error_log [error] +--- timeout: 10 @@ -2092,6 +2093,7 @@ run posted requests --- no_error_log [error] +--- timeout: 10 From 410930fa32af749cd87721a4bc85e3a45b15ea99 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 7 Sep 2013 23:23:18 -0700 Subject: [PATCH 0225/1981] feature: added support for raw downstream cosocket via the ngx.req.socket(true) API, upon which http upgrading protocols like WebSocket can be implemented with pure Lua. --- src/ngx_http_lua_common.h | 9 +- src/ngx_http_lua_output.c | 18 + src/ngx_http_lua_req_body.c | 4 +- src/ngx_http_lua_socket_tcp.c | 235 ++++++++--- src/ngx_http_lua_socket_tcp.h | 3 +- src/ngx_http_lua_util.c | 41 +- t/116-raw-req-socket.t | 687 +++++++++++++++++++++++++++++++++ t/117-raw-req-socket-timeout.t | 118 ++++++ 8 files changed, 1044 insertions(+), 71 deletions(-) create mode 100644 t/116-raw-req-socket.t create mode 100644 t/117-raw-req-socket-timeout.t diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 85a2ad48ae..4d1b3a9cd4 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -330,9 +330,8 @@ typedef struct ngx_http_lua_ctx_s { ngx_int_t exit_code; - ngx_http_lua_co_ctx_t *req_body_reader_co_ctx; /* co ctx for the coroutine - reading the request - body */ + ngx_http_lua_co_ctx_t *downstream_co_ctx; /* co ctx for the coroutine + reading the request body */ ngx_uint_t index; /* index of the current subrequest in its parent @@ -386,6 +385,10 @@ typedef struct ngx_http_lua_ctx_s { unsigned seen_last_in_filter:1; /* used by body_filter_by_lua* */ unsigned seen_last_for_subreq:1; /* used by body capture filter */ + unsigned writing_raw_req_socket:1; /* used by raw downstream + socket */ + unsigned acquired_raw_req_socket:1; /* whether a raw req socket + is acquired */ } ngx_http_lua_ctx_t; diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 8be60a258b..29cc8735fc 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -66,6 +66,12 @@ ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + if (ctx->acquired_raw_req_socket) { + lua_pushnil(L); + lua_pushliteral(L, "raw request socket acquired"); + return 2; + } + if (r->header_only) { lua_pushnil(L); lua_pushliteral(L, "header only"); @@ -488,6 +494,12 @@ ngx_http_lua_ngx_flush(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + if (ctx->acquired_raw_req_socket) { + lua_pushnil(L); + lua_pushliteral(L, "raw request socket acquired"); + return 2; + } + coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); @@ -636,6 +648,12 @@ ngx_http_lua_ngx_eof(lua_State *L) return luaL_error(L, "no ctx found"); } + if (ctx->acquired_raw_req_socket) { + lua_pushnil(L); + lua_pushliteral(L, "raw request socket acquired"); + return 2; + } + if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index a11075a84e..c31ef765a3 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -142,7 +142,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) "interruptions"); ctx->waiting_more_body = 1; - ctx->req_body_reader_co_ctx = coctx; + ctx->downstream_co_ctx = coctx; coctx->cleanup = ngx_http_lua_req_body_cleanup; coctx->data = r; @@ -175,7 +175,7 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) if (ctx->waiting_more_body) { ctx->waiting_more_body = 0; - coctx = ctx->req_body_reader_co_ctx; + coctx = ctx->downstream_co_ctx; ctx->cur_co_ctx = coctx; coctx->cleanup = NULL; diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 27f133a999..6faf9b764a 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -114,6 +114,7 @@ enum { static char ngx_http_lua_req_socket_metatable_key; +static char ngx_http_lua_raw_req_socket_metatable_key; static char ngx_http_lua_tcp_socket_metatable_key; @@ -148,6 +149,25 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{req socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + lua_createtable(L, 0 /* narr */, 3 /* nrec */); + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); + lua_setfield(L, -2, "receive"); + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); + lua_setfield(L, -2, "receiveuntil"); + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout); + lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ + + /* {{{raw req socket object metatable */ + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); lua_createtable(L, 0 /* narr */, 4 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_tcp_receive); @@ -156,6 +176,9 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_send); + lua_setfield(L, -2, "send"); + lua_pushcfunction(L, ngx_http_lua_socket_tcp_settimeout); lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ @@ -380,7 +403,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) return 2; } - if (u->is_downstream) { + if (u->body_downstream || u->raw_downstream) { return luaL_error(L, "attempt to re-connect a request socket"); } @@ -1134,7 +1157,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { r->read_event_handler = ngx_http_lua_req_socket_rev_handler; } @@ -1181,8 +1204,8 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) coctx->data = u; - if (u->is_downstream) { - ctx->req_body_reader_co_ctx = coctx; + if (u->raw_downstream || u->body_downstream) { + ctx->downstream_co_ctx = coctx; } return lua_yield(L, 0); @@ -1370,7 +1393,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, "uri:\"%V?%V\"", (int) u->waiting, (int) u->eof, &r->uri, &r->args); - if (u->is_downstream + if (u->body_downstream && b->last == b->pos && r->request_body->rest == 0) { @@ -1421,7 +1444,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, /* rc == NGX_AGAIN */ - if (u->is_downstream && r->request_body->rest == 0) { + if (u->body_downstream && r->request_body->rest == 0) { u->eof = 1; } @@ -1448,7 +1471,26 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, size = b->end - b->last; } - if (u->is_downstream) { + if (u->raw_downstream) { + preread = r->header_in->last - r->header_in->pos; + + if (preread) { + + if (size > preread) { + size = preread; + } + + ngx_http_lua_probe_req_socket_consume_preread(r, + r->header_in->pos, + size); + + b->last = ngx_copy(b->last, r->header_in->pos, size); + r->header_in->pos += size; + continue; + } + + } else if (u->body_downstream) { + if (r->request_body->rest == 0) { dd("request body rest is zero"); @@ -1530,7 +1572,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (n == 0) { - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -1543,7 +1585,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, /* llcf->check_client_abort == 0 */ - if (r->request_body->rest) { + if (u->body_downstream && r->request_body->rest) { ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); return NGX_ERROR; @@ -1567,7 +1609,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, b->last += n; - if (u->is_downstream) { + if (u->body_downstream) { r->request_length += n; r->request_body->rest -= n; } @@ -1648,7 +1690,13 @@ ngx_http_lua_socket_tcp_send(lua_State *L) return 2; } - if (u->is_downstream) { + if (u->raw_downstream && r->connection->buffered) { + lua_pushnil(L); + lua_pushliteral(L, "socket busy"); + return 2; + } + + if (u->body_downstream) { return luaL_error(L, "attempt to write to request sockets"); } @@ -1736,6 +1784,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L) /* rc == NGX_AGAIN */ ctx->cur_co_ctx->cleanup = ngx_http_lua_tcp_socket_cleanup; + ctx->writing_raw_req_socket = 1; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -1751,7 +1800,6 @@ ngx_http_lua_socket_tcp_send(lua_State *L) dd("setting data to %p", u); coctx = ctx->cur_co_ctx; - coctx->data = u; return lua_yield(L, 0); @@ -1791,7 +1839,7 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); #if 1 - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->check_client_abort) { @@ -1890,7 +1938,7 @@ ngx_http_lua_socket_tcp_close(lua_State *L) return 2; } - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { lua_pushnil(L); lua_pushliteral(L, "attempt to close a request socket"); return 2; @@ -2075,6 +2123,13 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, dd("lua connection log: %p", c->log); + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); + return NGX_ERROR; + } + b = u->request_bufs->buf; for (;;) { @@ -2091,12 +2146,6 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, ngx_del_timer(c->write); } - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_ERROR); - return NGX_ERROR; - } #if defined(nginx_version) && nginx_version >= 1001004 ngx_chain_update_chains(r->pool, @@ -2135,6 +2184,10 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, /* n == NGX_AGAIN */ + if (u->raw_downstream) { + ctx->writing_raw_req_socket = 1; + } + u->write_event_handler = ngx_http_lua_socket_send_handler; u->read_event_handler = ngx_http_lua_socket_dummy_handler; @@ -2343,7 +2396,7 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, u->cleanup = NULL; } - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { if (r->connection->read->timer_set) { ngx_del_timer(r->connection->read); } @@ -2650,7 +2703,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) u->length = (size_t) bytes; u->rest = u->length; - if (u->is_downstream) { + if (u->raw_downstream || u->body_downstream) { r->read_event_handler = ngx_http_lua_req_socket_rev_handler; } @@ -2697,8 +2750,8 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) coctx->data = u; - if (u->is_downstream) { - ctx->req_body_reader_co_ctx = coctx; + if (u->raw_downstream || u->body_downstream) { + ctx->downstream_co_ctx = coctx; } return lua_yield(L, 0); @@ -3018,6 +3071,7 @@ ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L) static int ngx_http_lua_req_socket(lua_State *L) { + int n, raw; ngx_peer_connection_t *pc; ngx_http_lua_loc_conf_t *llcf; ngx_connection_t *c; @@ -3029,7 +3083,15 @@ ngx_http_lua_req_socket(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; - if (lua_gettop(L) != 0) { + n = lua_gettop(L); + if (n == 0) { + raw = 0; + + } else if (n == 1) { + raw = lua_toboolean(L, 1); + lua_pop(L, 1); + + } else { return luaL_error(L, "expecting zero arguments, but got %d", lua_gettop(L)); } @@ -3058,46 +3120,98 @@ ngx_http_lua_req_socket(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - if (r->request_body) { + if (raw) { +#if !defined(nginx_version) || nginx_version < 1003013 lua_pushnil(L); - lua_pushliteral(L, "request body already exists"); + lua_pushliteral(L, "nginx version too old"); return 2; - } +#else + if (!r->request_body) { + lua_pushnil(L); + lua_pushliteral(L, "requesty body not read yet"); + return 2; + } - if (r->discard_body) { - lua_pushnil(L); - lua_pushliteral(L, "request body discarded"); - return 2; - } + if (r->connection->buffered) { + lua_pushnil(L); + lua_pushliteral(L, "pending data to write"); + return 2; + } - dd("req content length: %d", (int) r->headers_in.content_length_n); + if (ctx->buffering) { + lua_pushnil(L); + lua_pushliteral(L, "http 1.0 buffering"); + return 2; + } - if (r->headers_in.content_length_n <= 0) { - lua_pushnil(L); - lua_pushliteral(L, "no body"); - return 2; - } + if (!r->header_sent) { + lua_pushnil(L); + lua_pushliteral(L, "response header not sent yet"); + return 2; + } - if (ngx_http_lua_test_expect(r) != NGX_OK) { - lua_pushnil(L); - lua_pushliteral(L, "test expect failed"); - return 2; - } + dd("ctx acquired raw req socket: %d", ctx->acquired_raw_req_socket); - /* prevent other request body reader from running */ + if (ctx->acquired_raw_req_socket) { + lua_pushnil(L); + lua_pushliteral(L, "duplicate call"); + return 2; + } - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); - if (rb == NULL) { - return luaL_error(L, "out of memory"); - } + ctx->acquired_raw_req_socket = 1; + r->keepalive = 0; +#endif - rb->rest = r->headers_in.content_length_n; + } else { + /* request body reader */ - r->request_body = rb; + if (r->request_body) { + lua_pushnil(L); + lua_pushliteral(L, "request body already exists"); + return 2; + } + + if (r->discard_body) { + lua_pushnil(L); + lua_pushliteral(L, "request body discarded"); + return 2; + } + + dd("req content length: %d", (int) r->headers_in.content_length_n); + + if (r->headers_in.content_length_n <= 0) { + lua_pushnil(L); + lua_pushliteral(L, "no body"); + return 2; + } + + if (ngx_http_lua_test_expect(r) != NGX_OK) { + lua_pushnil(L); + lua_pushliteral(L, "test expect failed"); + return 2; + } + + /* prevent other request body reader from running */ + + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { + return luaL_error(L, "out of memory"); + } + + rb->rest = r->headers_in.content_length_n; + + r->request_body = rb; + } lua_createtable(L, 3 /* narr */, 1 /* nrec */); /* the object */ - lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + if (raw) { + lua_pushlightuserdata(L, &ngx_http_lua_raw_req_socket_metatable_key); + + } else { + lua_pushlightuserdata(L, &ngx_http_lua_req_socket_metatable_key); + } + lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -3117,7 +3231,12 @@ ngx_http_lua_req_socket(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); - u->is_downstream = 1; + if (raw) { + u->raw_downstream = 1; + + } else { + u->body_downstream = 1; + } coctx = ctx->cur_co_ctx; @@ -3154,12 +3273,18 @@ ngx_http_lua_req_socket(lua_State *L) dd("setting data to %p", u); coctx->data = u; - ctx->req_body_reader_co_ctx = coctx; + ctx->downstream_co_ctx = coctx; if (c->read->timer_set) { ngx_del_timer(c->read); } + if (raw) { + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + } + lua_settop(L, 1); return 1; } @@ -3180,7 +3305,7 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) return; } - coctx = ctx->req_body_reader_co_ctx; + coctx = ctx->downstream_co_ctx; u = coctx->data; if (u) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index e1a7688198..f977ef7133 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -88,7 +88,8 @@ struct ngx_http_lua_socket_tcp_upstream_s { unsigned no_close:1; unsigned waiting:1; unsigned eof:1; - unsigned is_downstream:1; + unsigned body_downstream:1; + unsigned raw_downstream:1; }; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 04d29532cb..813cf78172 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -511,8 +511,8 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_loc_conf_t *llcf; #if 1 - if (ctx->eof) { - dd("ctx->eof already set"); + if (ctx->acquired_raw_req_socket || ctx->eof) { + dd("ctx->eof already set or raw req socket already acquired"); return NGX_OK; } #endif @@ -1517,16 +1517,15 @@ ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r) { ngx_int_t rc; - ngx_http_lua_ctx_t *ctx; - ngx_connection_t *c; ngx_event_t *wev; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_http_core_loc_conf_t *clcf; - c = r->connection; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua run write event handler"); + ngx_http_lua_socket_tcp_upstream_t *u; + c = r->connection; wev = c->write; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -1534,9 +1533,14 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_ERROR; } + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua run write event handler: timedout:%ud, ready:%ud, " + "writing_raw_req_socket:%ud", + wev->timedout, wev->ready, ctx->writing_raw_req_socket); + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); - if (wev->timedout) { + if (wev->timedout && !ctx->writing_raw_req_socket) { if (!wev->delayed) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); @@ -1564,10 +1568,27 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (!wev->ready) { + if (!wev->ready && !wev->timedout) { goto useless; } + if (ctx->writing_raw_req_socket) { + ctx->writing_raw_req_socket = 0; + + coctx = ctx->downstream_co_ctx; + if (coctx == NULL) { + return NGX_ERROR; + } + + u = coctx->data; + if (u == NULL) { + return NGX_ERROR; + } + + u->write_event_handler(r, u); + return NGX_DONE; + } + if (c->buffered) { rc = ngx_http_lua_flush_pending_output(r, ctx); if (rc != NGX_OK) { diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t new file mode 100644 index 0000000000..e26b1367cc --- /dev/null +++ b/t/116-raw-req-socket.t @@ -0,0 +1,687 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use t::TestNginxLua; + +repeat_each(2); + +plan tests => repeat_each() * 25; + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +#log_level 'warn'; +log_level 'debug'; + +#no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + server_tokens off; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /mysock HTTP/1.1\\r\\nUpgrade: mysock\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\nhello" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local data, err, partial = reader() + if not data then + ngx.say("no response header found") + return + end + + local msg, err = sock:receive() + if not msg then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("msg: ", msg) + + ok, err = sock:close() + if not ok then + ngx.say("failed to close socket: ", err) + return + end + '; + } + + location = /mysock { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return + end + + local bytes, err = sock:send("1: received: " .. data .. "\\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return + end + '; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +msg: 1: received: hello +--- no_error_log +[error] + + + +=== TEST 2: header not sent yet +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.status = 101 + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.0\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- ignore_response +--- error_log +server: failed to get raw req socket: response header not sent yet + + + +=== TEST 3: http 1.0 buffering +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.say("hello") + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.0\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- stap2 +F(ngx_http_header_filter) { + println("header filter") +} +F(ngx_http_lua_req_socket) { + println("lua req socket") +} +--- ignore_response +--- error_log +server: failed to get raw req socket: http 1.0 buffering + + + +=== TEST 4: multiple raw req sockets +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.say("hello") + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + local sock2, err = ngx.req.socket(true) + if not sock2 then + ngx.log(ngx.ERR, "server: failed to get raw req socket2: ", err) + return + end + + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- stap2 +F(ngx_http_header_filter) { + println("header filter") +} +F(ngx_http_lua_req_socket) { + println("lua req socket") +} +--- ignore_response +--- error_log +server: failed to get raw req socket2: duplicate call + + + +=== TEST 5: ngx.say after ngx.req.socket(true) +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + local ok, err = ngx.say("ok") + if not ok then + ngx.log(ngx.ERR, "failed to say: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- ignore_response +--- error_log +failed to say: raw request socket acquired + + + +=== TEST 6: ngx.print after ngx.req.socket(true) +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + local ok, err = ngx.print("ok") + if not ok then + ngx.log(ngx.ERR, "failed to print: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- ignore_response +--- error_log +failed to print: raw request socket acquired + + + +=== TEST 7: ngx.eof after ngx.req.socket(true) +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + local ok, err = ngx.eof() + if not ok then + ngx.log(ngx.ERR, "failed to eof: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- ignore_response +--- error_log +failed to eof: raw request socket acquired + + + +=== TEST 8: ngx.flush after ngx.req.socket(true) +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + local ok, err = ngx.flush() + if not ok then + ngx.log(ngx.ERR, "failed to flush: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket +\r +hello" +--- ignore_response +--- error_log +failed to flush: raw request socket acquired + + + +=== TEST 9: receive timeout +--- config + server_tokens off; + postpone_output 1; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.req.read_body() + ngx.flush(true) + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + sock:settimeout(100) + + local data, err, partial = sock:receive(10) + if not data then + ngx.log(ngx.ERR, "server: 1: failed to receive: ", err, ", received: ", partial) + end + + data, err, partial = sock:receive(10) + if not data then + ngx.log(ngx.ERR, "server: 2: failed to receive: ", err, ", received: ", partial) + end + + ngx.exit(444) + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket\r +Connection: close\r +\r +ab" +--- ignore_response +--- wait: 0.1 +--- error_log +lua tcp socket read timed out +server: 1: failed to receive: timeout, received: ab, +server: 2: failed to receive: timeout, received: , +--- no_error_log +[alert] + + + +=== TEST 10: on_abort called during ngx.sleep() +--- config + server_tokens off; + lua_check_client_abort on; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /mysock HTTP/1.1\\r\\nUpgrade: mysock\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\nhello" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local data, err, partial = reader() + if not data then + ngx.say("no response header found") + return + end + + local msg, err = sock:receive() + if not msg then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("msg: ", msg) + + ngx.sleep(0.1) + + ok, err = sock:close() + if not ok then + ngx.say("failed to close socket: ", err) + return + end + '; + } + + location = /mysock { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + ngx.flush(true) + + local ok, err = ngx.on_abort(function (premature) ngx.log(ngx.WARN, "mysock handler aborted") end) + if not ok then + ngx.log(ngx.ERR, "failed to set on_abort handler: ", err) + return + end + + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return + end + + local bytes, err = sock:send("1: received: " .. data .. "\\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return + end + + ngx.sleep(1) + '; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +msg: 1: received: hello +--- error_log +mysock handler aborted +--- no_error_log +[error] +--- wait: 0.1 + + + +=== TEST 11: on_abort called during sock:receive() +--- config + server_tokens off; + lua_check_client_abort on; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /mysock HTTP/1.1\\r\\nUpgrade: mysock\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\nhello" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local data, err, partial = reader() + if not data then + ngx.say("no response header found") + return + end + + local msg, err = sock:receive() + if not msg then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("msg: ", msg) + + ngx.sleep(0.1) + + ok, err = sock:close() + if not ok then + ngx.say("failed to close socket: ", err) + return + end + '; + } + + location = /mysock { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + ngx.flush(true) + + local ok, err = ngx.on_abort(function (premature) ngx.log(ngx.WARN, "mysock handler aborted") end) + if not ok then + ngx.log(ngx.ERR, "failed to set on_abort handler: ", err) + return + end + + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return + end + + local bytes, err = sock:send("1: received: " .. data .. "\\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.WARN, "failed to receive a line: ", err) + return + end + '; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +msg: 1: received: hello +--- error_log +failed to receive a line: client aborted +--- no_error_log +[error] +--- wait: 0.1 + + + +=== TEST 12: receiveuntil +--- config + server_tokens off; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /mysock HTTP/1.1\\r\\nUpgrade: mysock\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\nhello" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local bytes, err = sock:send(", ") + if not bytes then + ngx.say("failed to send packet 1: ", err) + return + end + + local bytes, err = sock:send("world") + if not bytes then + ngx.say("failed to send packet 2: ", err) + return + end + + local reader = sock:receiveuntil("\\r\\n\\r\\n") + local data, err, partial = reader() + if not data then + ngx.say("no response header found") + return + end + + local msg, err = sock:receive() + if not msg then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("msg: ", msg) + + ok, err = sock:close() + if not ok then + ngx.say("failed to close socket: ", err) + return + end + '; + } + + location = /mysock { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + ngx.flush(true) + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local reader = sock:receiveuntil("rld") + local data, err = reader() + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return + end + + local bytes, err = sock:send("1: received: " .. data .. "\\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return + end + '; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +msg: 1: received: hello, wo +--- no_error_log +[error] + diff --git a/t/117-raw-req-socket-timeout.t b/t/117-raw-req-socket-timeout.t new file mode 100644 index 0000000000..93405ab86a --- /dev/null +++ b/t/117-raw-req-socket-timeout.t @@ -0,0 +1,118 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +BEGIN { + if (!defined $ENV{LD_PRELOAD}) { + $ENV{LD_PRELOAD} = ''; + } + + if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { + $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; + } + + if ($ENV{MOCKEAGAIN} eq 'r') { + $ENV{MOCKEAGAIN} = 'rw'; + + } else { + $ENV{MOCKEAGAIN} = 'w'; + } + + $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; + $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'hello, world'; + $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; +} + +use lib 'lib'; +use t::TestNginxLua; +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: pending response header data +--- config + server_tokens off; + postpone_output 1; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.req.read_body() + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket\r +Connection: close\r +\r +" +--- stap2 +F(ngx_http_header_filter) { + println("header filter") +} +F(ngx_http_lua_req_socket) { + println("lua req socket") +} +--- response_body +--- error_log +server: failed to get raw req socket: pending data to write + + + +=== TEST 2: send timeout +--- config + server_tokens off; + postpone_output 1; + location = /t { + content_by_lua ' + ngx.send_headers() + ngx.req.read_body() + ngx.flush(true) + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + sock:settimeout(100) + local ok, err = sock:send("hello, world!") + if not ok then + ngx.log(ngx.ERR, "server: failed to send: ", err) + end + ngx.exit(444) + '; + } + +--- raw_request eval +"GET /t HTTP/1.1\r +Host: localhost\r +Upgrade: mysocket\r +Connection: close\r +\r +" +--- ignore_response +--- error_log +lua tcp socket write timed out +server: failed to send: timeout +--- no_error_log +[alert] + From 4c6dc4f7a2889e256dc2b88506734ef55d5422b0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 8 Sep 2013 16:15:54 -0700 Subject: [PATCH 0226/1981] updated docs to reflect recent changes. --- README | 17 +++++++++++++++-- README.markdown | 8 +++++++- doc/HttpLuaModule.wiki | 8 +++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/README b/README index e7eb845777..0ab9b1e1ae 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.7 - () released on 2 + This document describes ngx_lua v0.8.8 + () released on 8 September 2013. Synopsis @@ -4677,6 +4677,9 @@ Nginx API for Lua It is important here to call the settimeout method *before* calling this method. + In case of any connection errors, this method always automatically + closes the current connection. + This feature was first introduced in the "v0.5.0rc1" release. tcpsock:receive @@ -4730,6 +4733,11 @@ Nginx API for Lua It is important here to call the settimeout method *before* calling this method. + Since the "v0.8.8" release, this method no longer automatically closes + the current connection when the read timeout error happens. For other + connection errors, this method always automatically closes the + connection. + This feature was first introduced in the "v0.5.0rc1" release. tcpsock:receiveuntil @@ -4843,6 +4851,11 @@ Nginx API for Lua the example above will output "hello world _END_", including the pattern string "_END_" itself. + Since the "v0.8.8" release, this method no longer automatically closes + the current connection when the read timeout error happens. For other + connection errors, this method always automatically closes the + connection. + This method was first introduced in the "v0.5.0rc1" release. tcpsock:close diff --git a/README.markdown b/README.markdown index 048066dc2e..f8115b42e8 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 2 September 2013. +This document describes ngx_lua [v0.8.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 September 2013. Synopsis ======== @@ -4235,6 +4235,8 @@ Timeout for the sending operation is controlled by the [lua_socket_send_timeout] It is important here to call the [settimeout](http://wiki.nginx.org/HttpLuaModule#tcpsock:settimeout) method *before* calling this method. +In case of any connection errors, this method always automatically closes the current connection. + This feature was first introduced in the `v0.5.0rc1` release. tcpsock:receive @@ -4274,6 +4276,8 @@ Timeout for the reading operation is controlled by the [lua_socket_read_timeout] It is important here to call the [settimeout](http://wiki.nginx.org/HttpLuaModule#tcpsock:settimeout) method *before* calling this method. +Since the `v0.8.8` release, this method no longer automatically closes the current connection when the read timeout error happens. For other connection errors, this method always automatically closes the connection. + This feature was first introduced in the `v0.5.0rc1` release. tcpsock:receiveuntil @@ -4365,6 +4369,8 @@ The `inclusive` takes a boolean value to control whether to include the pattern Then for the input data stream `"hello world _END_ blah blah blah"`, then the example above will output `hello world _END_`, including the pattern string `_END_` itself. +Since the `v0.8.8` release, this method no longer automatically closes the current connection when the read timeout error happens. For other connection errors, this method always automatically closes the connection. + This method was first introduced in the `v0.5.0rc1` release. tcpsock:close diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9f5d3311b7..732b1e4811 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.7] released on 2 September 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.8] released on 8 September 2013. = Synopsis = @@ -4091,6 +4091,8 @@ Timeout for the sending operation is controlled by the [[#lua_socket_send_timeou It is important here to call the [[#tcpsock:settimeout|settimeout]] method ''before'' calling this method. +In case of any connection errors, this method always automatically closes the current connection. + This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receive == @@ -4129,6 +4131,8 @@ Timeout for the reading operation is controlled by the [[#lua_socket_read_timeou It is important here to call the [[#tcpsock:settimeout|settimeout]] method ''before'' calling this method. +Since the v0.8.8 release, this method no longer automatically closes the current connection when the read timeout error happens. For other connection errors, this method always automatically closes the connection. + This feature was first introduced in the v0.5.0rc1 release. == tcpsock:receiveuntil == @@ -4219,6 +4223,8 @@ The inclusive takes a boolean value to control whether to include t Then for the input data stream "hello world _END_ blah blah blah", then the example above will output hello world _END_, including the pattern string _END_ itself. +Since the v0.8.8 release, this method no longer automatically closes the current connection when the read timeout error happens. For other connection errors, this method always automatically closes the connection. + This method was first introduced in the v0.5.0rc1 release. == tcpsock:close == From 5b7c567cb662627f3f2982e75ee078df1978ef4e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 8 Sep 2013 16:51:32 -0700 Subject: [PATCH 0227/1981] documented the "always_forward_body" option for ngx.location.capture() and ngx.location.capture_multi(). --- README | 61 ++++++++++++++++++++++-------------------- README.markdown | 4 ++- doc/HttpLuaModule.wiki | 4 ++- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/README b/README index 0ab9b1e1ae..e623c9896d 100644 --- a/README +++ b/README @@ -1803,35 +1803,41 @@ Nginx API for Lua supports the options: * "method" specify the subrequest's request method, which only accepts - constants like "ngx.HTTP_POST". =item * + constants like "ngx.HTTP_POST". - "body" specify the subrequest's request body (string value only). - =item * + * "body" specify the subrequest's request body (string value only). - "args" specify the subrequest's URI query arguments (both string - value and Lua tables are accepted) =item * + * "args" specify the subrequest's URI query arguments (both string + value and Lua tables are accepted) - "ctx" specify a Lua table to be the ngx.ctx table for the + * "ctx" specify a Lua table to be the ngx.ctx table for the subrequest. It can be the current request's ngx.ctx table, which effectively makes the parent and its subrequest to share exactly the same context table. This option was first introduced in the - "v0.3.1rc25" release. =item * + "v0.3.1rc25" release. - "vars" take a Lua table which holds the values to set the specified + * "vars" take a Lua table which holds the values to set the specified Nginx variables in the subrequest as this option's value. This - option was first introduced in the "v0.3.1rc31" release. =item * + option was first introduced in the "v0.3.1rc31" release. - "copy_all_vars" specify whether to copy over all the Nginx variable + * "copy_all_vars" specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first - introduced in the "v0.3.1rc31" release. =item * + introduced in the "v0.3.1rc31" release. - "share_all_vars" specify whether to share all the Nginx variables of + * "share_all_vars" specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. + * "always_forward_body" when set to true, the current (parent) + request's request body will always be forwarded to the subrequest + being created if the "body" option is not specified. By default, + this option is false and when the "body" option is not specified, + the request body of the current (parent) request is only forwarded + when the subrequest takes the "PUT" or "POST" request method. + Issuing a POST subrequest, for example, can be done as follows res = ngx.location.capture( @@ -2008,9 +2014,9 @@ Nginx API for Lua headers should be ignored by setting proxy_pass_request_headers to "off" in subrequest locations. - When the "body" option is not specified, the "POST" and "PUT" - subrequests will inherit the request bodies of the parent request (if - any). + When the "body" option is not specified and the "always_forward_body" + option is false (the default value), the "POST" and "PUT" subrequests + will inherit the request bodies of the parent request (if any). There is a hard-coded upper limit on the number of concurrent subrequests possible for every main request. In older versions of Nginx, @@ -5004,28 +5010,25 @@ Nginx API for Lua Retrieves the current running phase name. Possible return values are - * "init" for the context of init_by_lua or init_by_lua_file. =item * + * "init" for the context of init_by_lua or init_by_lua_file. - "set" for the context of set_by_lua or set_by_lua_file. =item * + * "set" for the context of set_by_lua or set_by_lua_file. - "rewrite" for the context of rewrite_by_lua or rewrite_by_lua_file. - =item * + * "rewrite" for the context of rewrite_by_lua or rewrite_by_lua_file. - "access" for the context of access_by_lua or access_by_lua_file. - =item * + * "access" for the context of access_by_lua or access_by_lua_file. - "content" for the context of content_by_lua or content_by_lua_file. - =item * + * "content" for the context of content_by_lua or content_by_lua_file. - "header_filter" for the context of header_filter_by_lua or - header_filter_by_lua_file. =item * + * "header_filter" for the context of header_filter_by_lua or + header_filter_by_lua_file. - "body_filter" for the context of body_filter_by_lua or - body_filter_by_lua_file. =item * + * "body_filter" for the context of body_filter_by_lua or + body_filter_by_lua_file. - "log" for the context of log_by_lua or log_by_lua_file. =item * + * "log" for the context of log_by_lua or log_by_lua_file. - "timer" for the context of user callback functions for ngx.timer.*. + * "timer" for the context of user callback functions for ngx.timer.*. This API was first introduced in the "v0.5.10" release. diff --git a/README.markdown b/README.markdown index f8115b42e8..8f35553b3f 100644 --- a/README.markdown +++ b/README.markdown @@ -1626,6 +1626,8 @@ argument, which supports the options: specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the `v0.3.1rc31` release. * `share_all_vars` specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. +* `always_forward_body` + when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the `body` option is not specified. By default, this option is false and when the `body` option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the `PUT` or `POST` request method. Issuing a POST subrequest, for example, can be done as follows @@ -1816,7 +1818,7 @@ subrequests, an "Accept-Encoding: gzip" header in the main request may result in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [proxy_pass_request_headers](http://wiki.nginx.org/HttpProxyModule#proxy_pass_request_headers) to `off` in subrequest locations. -When the `body` option is not specified, the `POST` and `PUT` subrequests will inherit the request bodies of the parent request (if any). +When the `body` option is not specified and the `always_forward_body` option is false (the default value), the `POST` and `PUT` subrequests will inherit the request bodies of the parent request (if any). There is a hard-coded upper limit on the number of concurrent subrequests possible for every main request. In older versions of Nginx, the limit was `50` concurrent subrequests and in more recent versions, Nginx `1.1.x` onwards, this was increased to `200` concurrent subrequests. When this limit is exceeded, the following error message is added to the `error.log` file: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 732b1e4811..c4ab9d6952 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1567,6 +1567,8 @@ argument, which supports the options: : specify whether to copy over all the Nginx variable values of the current request to the subrequest in question. modifications of the nginx variables in the subrequest will not affect the current (parent) request. This option was first introduced in the v0.3.1rc31 release. * share_all_vars : specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. +* always_forward_body +: when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the body option is not specified. By default, this option is false and when the body option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the PUT or POST request method. Issuing a POST subrequest, for example, can be done as follows @@ -1757,7 +1759,7 @@ subrequests, an "Accept-Encoding: gzip" header in the main request may result in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [[HttpProxyModule#proxy_pass_request_headers|proxy_pass_request_headers]] to off in subrequest locations. -When the body option is not specified, the POST and PUT subrequests will inherit the request bodies of the parent request (if any). +When the body option is not specified and the always_forward_body option is false (the default value), the POST and PUT subrequests will inherit the request bodies of the parent request (if any). There is a hard-coded upper limit on the number of concurrent subrequests possible for every main request. In older versions of Nginx, the limit was 50 concurrent subrequests and in more recent versions, Nginx 1.1.x onwards, this was increased to 200 concurrent subrequests. When this limit is exceeded, the following error message is added to the error.log file: From 38ebe9a3171d448e1f3ecb03a38cce52d3e01381 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 9 Sep 2013 15:09:41 -0700 Subject: [PATCH 0228/1981] bugfix: we did not honor the tcp_nodelay config directive in the raw downstream cosockets. --- src/ngx_http_lua_socket_tcp.c | 39 +++++++++++++++++++++++++++++++---- t/116-raw-req-socket.t | 4 +++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 6faf9b764a..f54a1b8c4b 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3071,7 +3071,7 @@ ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L) static int ngx_http_lua_req_socket(lua_State *L) { - int n, raw; + int n, raw, tcp_nodelay; ngx_peer_connection_t *pc; ngx_http_lua_loc_conf_t *llcf; ngx_connection_t *c; @@ -3080,6 +3080,7 @@ ngx_http_lua_req_socket(lua_State *L) ngx_http_request_body_t *rb; ngx_http_cleanup_t *cln; ngx_http_lua_co_ctx_t *coctx; + ngx_http_core_loc_conf_t *clcf; ngx_http_lua_socket_tcp_upstream_t *u; @@ -3120,6 +3121,8 @@ ngx_http_lua_req_socket(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + c = r->connection; + if (raw) { #if !defined(nginx_version) || nginx_version < 1003013 lua_pushnil(L); @@ -3132,7 +3135,7 @@ ngx_http_lua_req_socket(lua_State *L) return 2; } - if (r->connection->buffered) { + if (c->buffered) { lua_pushnil(L); lua_pushliteral(L, "pending data to write"); return 2; @@ -3158,6 +3161,35 @@ ngx_http_lua_req_socket(lua_State *L) return 2; } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->tcp_nodelay) { + tcp_nodelay = 1; + + if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua raw req socket tcp_nodelay"); + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) + == -1) + { + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->log_socket_errors) { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) " + "failed"); + } + + lua_pushnil(L); + lua_pushliteral(L, "setsocketopt tcp_nodelay failed"); + return 2; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + } + ctx->acquired_raw_req_socket = 1; r->keepalive = 0; #endif @@ -3264,10 +3296,9 @@ ngx_http_lua_req_socket(lua_State *L) pc = &u->peer; - pc->log = r->connection->log; + pc->log = c->log; pc->log_error = NGX_ERROR_ERR; - c = r->connection; pc->connection = c; dd("setting data to %p", u); diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index e26b1367cc..3b7d7a4b1e 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 25; +plan tests => repeat_each() * 26; our $HtmlDir = html_dir; @@ -100,6 +100,8 @@ __DATA__ GET /t --- response_body msg: 1: received: hello +--- error_log +lua raw req socket tcp_nodelay --- no_error_log [error] From 36157b4cd726cf0d1d45145f4363256009a77ea6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 13 Sep 2013 12:22:29 -0700 Subject: [PATCH 0229/1981] bugfix: tcpsock:receive(0) could hang when no data arrived; now it always returns an empty string immediately. this new behavior diverges from LuaSocket though. --- src/ngx_http_lua_socket_tcp.c | 7 +++++ t/058-tcp-socket.t | 49 ++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 27f133a999..b6e9be95ba 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1095,6 +1095,13 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) return luaL_argerror(L, 2, "bad pattern argument"); } +#if 1 + if (bytes == 0) { + lua_pushliteral(L, ""); + return 1; + } +#endif + u->input_filter = ngx_http_lua_socket_read_chunk; u->length = (size_t) bytes; u->rest = u->length; diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 217f3e4fbd..9a5b09d662 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 120; +plan tests => repeat_each() * 123; our $HtmlDir = html_dir; @@ -2490,3 +2490,50 @@ lua tcp socket read timed out --- no_error_log [alert] + + +=== TEST 41: receive(0) +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local data, err = sock:receive(0) + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", data) + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + '; + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +received: +close: 1 nil +--- no_error_log +[error] + From 8bbd6aae271952a538e6cdfd7ef6dc4a192979ce Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 13 Sep 2013 15:31:28 -0700 Subject: [PATCH 0230/1981] bugfix: the nginx core does not send a default status line for 101 status code. now we construct one for 101. --- src/ngx_http_lua_misc.c | 14 +++++++++++++- t/015-status.t | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 474aa15e5b..2f5842bd0f 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -126,7 +126,19 @@ ngx_http_lua_ngx_set(lua_State *L) /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); - r->headers_out.status_line.len = 0; + + if (r->headers_out.status == 101) { + /* + * XXX work-around a bug in the Nginx core that 101 does + * not have a default status line + */ + + ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); + + } else { + r->headers_out.status_line.len = 0; + } + return 0; } diff --git a/t/015-status.t b/t/015-status.t index c1836e71ce..5ec9bf3bf5 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -10,7 +10,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); #no_long_string(); @@ -218,3 +218,20 @@ Range: bytes=0-4 --- no_error_log [error] + + +=== TEST 13: 101 response has a complete status line +--- config + location /t { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + '; + } +--- request +GET /t +--- raw_response_headers_like: ^HTTP/1.1 101 Switching Protocols\r\n +--- error_code: 101 +--- no_error_log +[error] + From 22e09118b2383ea14a396d5f68598f2528d9916f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 13 Sep 2013 15:31:28 -0700 Subject: [PATCH 0231/1981] bugfix: the nginx core does not send a default status line for 101 status code. now we construct one for 101. --- src/ngx_http_lua_misc.c | 14 +++++++++++++- t/015-status.t | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 474aa15e5b..2f5842bd0f 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -126,7 +126,19 @@ ngx_http_lua_ngx_set(lua_State *L) /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); - r->headers_out.status_line.len = 0; + + if (r->headers_out.status == 101) { + /* + * XXX work-around a bug in the Nginx core that 101 does + * not have a default status line + */ + + ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); + + } else { + r->headers_out.status_line.len = 0; + } + return 0; } diff --git a/t/015-status.t b/t/015-status.t index c1836e71ce..5ec9bf3bf5 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -10,7 +10,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); #no_long_string(); @@ -218,3 +218,20 @@ Range: bytes=0-4 --- no_error_log [error] + + +=== TEST 13: 101 response has a complete status line +--- config + location /t { + content_by_lua ' + ngx.status = 101 + ngx.send_headers() + '; + } +--- request +GET /t +--- raw_response_headers_like: ^HTTP/1.1 101 Switching Protocols\r\n +--- error_code: 101 +--- no_error_log +[error] + From 7b726b32cd037ab1bebdbb0c870e8bf7dbd0600d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 14 Sep 2013 13:38:48 -0700 Subject: [PATCH 0232/1981] change: we now temporarily disable the Lua API functions ngx.location.capture, ngx.location.capture_multi, and ngx.req.socket that are known to have problems with the SPDY requests for now. we will fix them eventually in the near future. --- src/ngx_http_lua_socket_tcp.c | 6 ++++++ src/ngx_http_lua_subrequest.c | 6 ++++++ util/build2.sh | 1 + 3 files changed, 13 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index b6e9be95ba..32b763cd0e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3048,6 +3048,12 @@ ngx_http_lua_req_socket(lua_State *L) "subrequest"); } +#if (NGX_HTTP_SPDY) + if (r->spdy_stream) { + return luaL_error(L, "spdy not supported yet"); + } +#endif + #if nginx_version >= 1003009 if (r->headers_in.chunked) { lua_pushnil(L); diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index fb8d483598..3bba4726cd 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -162,6 +162,12 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "no request object found"); } +#if (NGX_HTTP_SPDY) + if (r->spdy_stream) { + return luaL_error(L, "spdy not supported yet"); + } +#endif + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); diff --git a/util/build2.sh b/util/build2.sh index 77d56fdb7a..8bc267911e 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -25,6 +25,7 @@ time ngx-build $force $version \ --add-module=$root/../ndk-nginx-module \ --add-module=$root/../set-misc-nginx-module \ --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:$LUAJIT_LIB:/usr/local/lib" \ + --with-http_spdy_module \ --without-mail_pop3_module \ --without-mail_imap_module \ --without-mail_smtp_module \ From 95e293160b9c3fa9dbd3a977ac35563ea63ce8b0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 14 Sep 2013 19:55:02 -0700 Subject: [PATCH 0233/1981] bugfix: the "pool" option value could not be nil in tcpsock:connect(). --- src/ngx_http_lua_socket_tcp.c | 4 ++++ t/058-tcp-socket.t | 40 ++++++++++++++++++++++++++++++++++- t/068-socket-keepalive.t | 10 +++++---- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 32b763cd0e..38d2b2a115 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -331,6 +331,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) break; + case LUA_TNIL: + lua_pop(L, 2); + break; + default: msg = lua_pushfstring(L, "bad \"pool\" option type: %s", luaL_typename(L, -1)); diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 9a5b09d662..b221c20695 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 123; +plan tests => repeat_each() * 126; our $HtmlDir = html_dir; @@ -2537,3 +2537,41 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 42: empty options table +--- config + server_tokens off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port, {}) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + '; + } + + location /foo { + content_by_lua 'ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +close: 1 nil +--- no_error_log +[error] + diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index f50c255b29..2f9b28ea0b 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -1256,10 +1256,12 @@ function go(port, pool) end --- request GET /t ---- response_body_like: 500 Internal Server Error ---- error_code: 500 ---- error_log -bad argument #3 to 'connect' (bad "pool" option type: nil) +--- response_body +connected: 1, reused: 0 +connected: 1, reused: 0 +--- error_code: 200 +--- no_error_log +[error] From 235875b5c6afd4961181fa9ead9c167dc865e737 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 14 Sep 2013 21:32:02 -0700 Subject: [PATCH 0234/1981] refactor: removed our own ctx->headers_sent field because we should used r->header_sent instead. --- src/ngx_http_lua_common.h | 3 --- src/ngx_http_lua_control.c | 7 +++---- src/ngx_http_lua_headers.c | 2 +- src/ngx_http_lua_misc.c | 6 +++--- src/ngx_http_lua_output.c | 4 ++-- src/ngx_http_lua_util.c | 18 ++++++++---------- 6 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 85a2ad48ae..c2467992f5 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -356,9 +356,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned exited:1; - unsigned headers_sent:1; /* 1: response header has been sent; - 0: header not sent yet */ - unsigned eof:1; /* 1: last_buf has been sent; 0: last_buf not sent yet */ diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 7142481c77..e14ab529e2 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -108,7 +108,6 @@ ngx_http_lua_ngx_exec(lua_State *L) if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { - ctx->headers_sent = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -173,7 +172,7 @@ ngx_http_lua_ngx_exec(lua_State *L) } } - if (ctx->headers_sent) { + if (r->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } @@ -237,7 +236,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) ngx_http_lua_check_if_abortable(L, ctx); - if (ctx->headers_sent) { + if (r->header_sent) { return luaL_error(L, "attempt to call ngx.redirect after sending out " "the headers"); } @@ -319,7 +318,7 @@ ngx_http_lua_ngx_exit(lua_State *L) return luaL_error(L, "attempt to abort with pending subrequests"); } - if (ctx->headers_sent + if (r->header_sent && rc >= NGX_HTTP_SPECIAL_RESPONSE && rc != NGX_HTTP_REQUEST_TIME_OUT && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 82b7e3d823..3afbd7ba76 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -452,7 +452,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_http_lua_check_fake_request2(L, r, ctx); - if (ctx->headers_sent) { + if (r->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " "set ngx.header.HEADER after sending out " "response headers"); diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 2f5842bd0f..d3b3173e72 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -81,9 +81,9 @@ ngx_http_lua_ngx_get(lua_State *L) ngx_http_lua_check_fake_request2(L, r, ctx); - dd("headers sent: %d", ctx->headers_sent); + dd("headers sent: %d", r->header_sent); - lua_pushboolean(L, ctx->headers_sent ? 1 : 0); + lua_pushboolean(L, r->header_sent ? 1 : 0); return 1; } @@ -115,7 +115,7 @@ ngx_http_lua_ngx_set(lua_State *L) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx->headers_sent) { + if (r->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to set ngx.status after sending out " "response headers"); diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 8be60a258b..f26f3d1e23 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -515,7 +515,7 @@ ngx_http_lua_ngx_flush(lua_State *L) } #if 1 - if (!ctx->headers_sent) { + if (!r->header_sent) { lua_pushnil(L); lua_pushliteral(L, "nothing to flush"); return 2; @@ -708,7 +708,7 @@ ngx_http_lua_ngx_send_headers(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - if (!ctx->headers_sent) { + if (!r->header_sent) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send headers"); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 04d29532cb..a1c4b1cf1a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -475,7 +475,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, { ngx_int_t rc; - if (!ctx->headers_sent) { + if (!r->header_sent) { if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; } @@ -492,7 +492,6 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, if (!ctx->buffering) { dd("sending headers"); rc = ngx_http_send_header(r); - ctx->headers_sent = 1; return rc; } } @@ -525,7 +524,7 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, if (llcf->http10_buffering && !ctx->buffering - && !ctx->headers_sent + && !r->header_sent && r->http_version < NGX_HTTP_VERSION_11 && r->headers_out.content_length_n < 0) { @@ -662,7 +661,7 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_chain_t *cl; ngx_int_t rc; - if (ctx->headers_sent) { + if (r->header_sent) { return NGX_OK; } @@ -687,7 +686,6 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, send: rc = ngx_http_send_header(r); - ctx->headers_sent = 1; return rc; } @@ -1436,15 +1434,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_request_cleanup(ctx, 0); - dd("headers sent? %d", ctx->headers_sent ? 1 : 0); + dd("headers sent? %d", r->header_sent ? 1 : 0); if (ctx->no_abort) { ctx->no_abort = 0; return NGX_ERROR; } - return ctx->headers_sent ? NGX_ERROR : - NGX_HTTP_INTERNAL_SERVER_ERROR; + return r->header_sent ? NGX_ERROR : + NGX_HTTP_INTERNAL_SERVER_ERROR; } /* being a user coroutine that has a parent */ @@ -1497,7 +1495,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " "user coroutine has no parent"); - return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; + return r->header_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; done: if (ctx->entered_content_phase && r->connection->fd != -1) { @@ -2212,7 +2210,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ctx->exit_code); #if 1 - if (!ctx->headers_sent + if (!r->header_sent && r->headers_out.status == 0 && ctx->exit_code >= NGX_HTTP_OK) { From a641101a5e99197f5be5ce3a007cf66ae6aeafc6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 15 Sep 2013 13:46:28 -0700 Subject: [PATCH 0235/1981] bumped version to 0.8.9. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index e623c9896d..aa53229cdd 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.8 - () released on 8 + This document describes ngx_lua v0.8.9 + () released on 15 September 2013. Synopsis diff --git a/README.markdown b/README.markdown index 8f35553b3f..d550952af0 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 September 2013. +This document describes ngx_lua [v0.8.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 15 September 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index c4ab9d6952..55ed170da5 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.8] released on 8 September 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.9] released on 15 September 2013. = Synopsis = From 8fdfc79838033d956b22e024da084d99ecd75bfa Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 17 Sep 2013 14:07:49 -0700 Subject: [PATCH 0236/1981] bugfix: use of the ctx->headers_sent field that was already removed. --- src/ngx_http_lua_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index b2dcfe0381..95752bc6ce 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -436,7 +436,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err, return NGX_ERROR; } - if (ctx->headers_sent + if (r->header_sent && status >= NGX_HTTP_SPECIAL_RESPONSE && status != NGX_HTTP_REQUEST_TIME_OUT && status != NGX_HTTP_CLIENT_CLOSED_REQUEST From c218ed706a06164844e0b15c12944a17a419a08e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 17 Sep 2013 15:09:46 -0700 Subject: [PATCH 0237/1981] testing: fixed the stap probes for the new ffi implementation. --- t/091-coroutine.t | 1 + t/StapThread.pm | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 4dc4c21217..d8970da0ad 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -71,6 +71,7 @@ M(http-lua-user-coroutine-create) { F(ngx_http_lua_ngx_exec) { println("exec") } F(ngx_http_lua_ngx_exit) { println("exit") } +F(ngx_http_lua_ffi_exit) { println("exit") } _EOC_ no_shuffle(); diff --git a/t/StapThread.pm b/t/StapThread.pm index ce3a9aa75c..e958863447 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -225,6 +225,7 @@ M(http-lua-user-coroutine-create) { F(ngx_http_lua_ngx_exec) { println("exec") } F(ngx_http_lua_ngx_exit) { println("exit") } +F(ngx_http_lua_ffi_exit) { println("exit") } F(ngx_http_lua_req_body_cleanup) { println("lua req body cleanup") @@ -242,6 +243,10 @@ F(ngx_http_lua_ngx_exit) { println("ngx.exit() called") } +F(ngx_http_lua_ffi_exit) { + println("ngx.exit() called") +} + F(ngx_http_lua_sleep_resume) { println("lua sleep resume") } From a98ff5f802d5a2fa5d65f489507d63e694b367ba Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 18 Sep 2013 12:13:43 -0700 Subject: [PATCH 0238/1981] docs: avoided using module() and also recommended the lua-releng tool to locate misuse of Lua globals. --- README | 64 +++++++++++++++++++++++++++--------------- README.markdown | 39 +++++++++++++++---------- doc/HttpLuaModule.wiki | 41 ++++++++++++++++----------- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/README b/README index aa53229cdd..fa8e5015c3 100644 --- a/README +++ b/README @@ -1422,12 +1422,14 @@ Nginx API for Lua local say = ngx.say - module(...) + local _M = {} - function foo(a) - say(a) + function _M.foo(a) + say(a) end + return _M + Use of the package.seeall () flag is strongly discouraged due to its various bad side-effects. @@ -5681,7 +5683,7 @@ Data Sharing within an Nginx Worker Here is a complete small example: -- mydata.lua - module(...) + local _M = {} local data = { dog = 3, @@ -5689,10 +5691,12 @@ Data Sharing within an Nginx Worker pig = 5, } - function get_age(name) + function _M.get_age(name) return data[name] end + return _M + and then accessing it from "nginx.conf": location /lua { @@ -5783,23 +5787,39 @@ Known Issues environment. So one will get Lua exception for accessing the "nil" value. - It is recommended to always place the following piece of code at the end - of Lua modules that use the I/O operations to prevent casual use of - module-level global variables that are shared among *all* requests: - - local class_mt = { - -- to prevent use of casual module global variables - __newindex = function (table, key, val) - error('attempt to write to undeclared variable "' .. key .. '"') - end - } - setmetatable(_M, class_mt) - - This will guarantee that local variables in the Lua module functions are - all declared with the "local" keyword, otherwise a runtime exception - will be thrown. It prevents undesirable race conditions while accessing - such variables. See Data Sharing within an Nginx Worker for the reasons - behind this. + Generally, use of Lua global variables is a really really bad idea in + the context of ngx_lua because + + 1. misuse of Lua globals has very bad side effects for concurrent + requests when these variables are actually supposed to be local + only, + + 2. Lua global variables require Lua table look-up in the global + environment (which is just a Lua table), which is kinda expensive, + and + + 3. some Lua global variable references are just typos, which are hard + to debug. + + It's *highly* recommended to always declare them via "local" in the + scope that is reasonable. + + To find out all the uses of Lua global variables in your Lua code, you + can run the lua-releng tool + () + across all your .lua source files: $ lua-releng Checking use of Lua + global variables in file lib/foo/bar.lua ... 1 [1489] SETGLOBAL 7 -1 ; + contains 55 [1506] GETGLOBAL 7 -3 ; setvar 3 [1545] GETGLOBAL 3 -4 ; + varexpand The output says that the line 1489 of file "lib/foo/bar.lua" + writes to a global variable named "contains", the line 1506 reads from + the global variable "setvar", and line 1545 reads the global + "varexpand". + + This tool will guarantee that local variables in the Lua module + functions are all declared with the "local" keyword, otherwise a runtime + exception will be thrown. It prevents undesirable race conditions while + accessing such variables. See Data Sharing within an Nginx Worker for + the reasons behind this. Locations Configured by Subrequest Directives of Other Modules The ngx.location.capture and ngx.location.capture_multi directives diff --git a/README.markdown b/README.markdown index d550952af0..b9fbb968a0 100644 --- a/README.markdown +++ b/README.markdown @@ -1251,12 +1251,14 @@ The packages can be introduced into external Lua modules like this: local say = ngx.say - module(...) + local _M = {} - function foo(a) - say(a) + function _M.foo(a) + say(a) end + return _M + Use of the [package.seeall](http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall) flag is strongly discouraged due to its various bad side-effects. @@ -5064,18 +5066,20 @@ Here is a complete small example: -- mydata.lua - module(...) - + local _M = {} + local data = { dog = 3, cat = 4, pig = 5, } - function get_age(name) + function _M.get_age(name) return data[name] end + return _M + and then accessing it from `nginx.conf`: @@ -5132,19 +5136,24 @@ Care must be taken when importing modules and this form should be used: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the package.loaded table for later reference, and `require()` has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. -It is recommended to always place the following piece of code at the end of Lua modules that use the I/O operations to prevent casual use of module-level global variables that are shared among *all* requests: +Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +1. misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, +1. Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and +1. some Lua global variable references are just typos, which are hard to debug. +It's *highly* recommended to always declare them via "local" in the scope that is reasonable. - local class_mt = { - -- to prevent use of casual module global variables - __newindex = function (table, key, val) - error('attempt to write to undeclared variable "' .. key .. '"') - end - } - setmetatable(_M, class_mt) +To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/agentzh/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: + + $ lua-releng + Checking use of Lua global variables in file lib/foo/bar.lua ... + 1 [1489] SETGLOBAL 7 -1 ; contains + 55 [1506] GETGLOBAL 7 -3 ; setvar + 3 [1545] GETGLOBAL 3 -4 ; varexpand +The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. -This will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker) for the reasons behind this. +This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker) for the reasons behind this. Locations Configured by Subrequest Directives of Other Modules -------------------------------------------------------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 55ed170da5..8e4474db71 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1201,11 +1201,13 @@ The packages can be introduced into external Lua modules like this: local say = ngx.say - module(...) + local _M = {} - function foo(a) - say(a) + function _M.foo(a) + say(a) end + + return _M Use of the [http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall package.seeall] flag is strongly discouraged due to its various bad side-effects. @@ -4896,17 +4898,19 @@ Here is a complete small example: -- mydata.lua - module(...) - + local _M = {} + local data = { dog = 3, cat = 4, pig = 5, } - function get_age(name) + function _M.get_age(name) return data[name] end + + return _M and then accessing it from nginx.conf: @@ -4960,19 +4964,24 @@ Care must be taken when importing modules and this form should be used: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the require() built-in in the package.loaded table for later reference, and require() has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the nil value. -It is recommended to always place the following piece of code at the end of Lua modules that use the I/O operations to prevent casual use of module-level global variables that are shared among ''all'' requests: +Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +# misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, +# Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and +# some Lua global variable references are just typos, which are hard to debug. - - local class_mt = { - -- to prevent use of casual module global variables - __newindex = function (table, key, val) - error('attempt to write to undeclared variable "' .. key .. '"') - end - } - setmetatable(_M, class_mt) +It's *highly* recommended to always declare them via "local" in the scope that is reasonable. + +To find out all the uses of Lua global variables in your Lua code, you can run the [https://github.com/agentzh/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all your .lua source files: + +$ lua-releng +Checking use of Lua global variables in file lib/foo/bar.lua ... + 1 [1489] SETGLOBAL 7 -1 ; contains + 55 [1506] GETGLOBAL 7 -3 ; setvar + 3 [1545] GETGLOBAL 3 -4 ; varexpand +The output says that the line 1489 of file lib/foo/bar.lua writes to a global variable named contains, the line 1506 reads from the global variable setvar, and line 1545 reads the global varexpand. -This will guarantee that local variables in the Lua module functions are all declared with the local keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [[#Data_Sharing_within_an_Nginx_Worker|Data Sharing within an Nginx Worker]] for the reasons behind this. +This tool will guarantee that local variables in the Lua module functions are all declared with the local keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [[#Data_Sharing_within_an_Nginx_Worker|Data Sharing within an Nginx Worker]] for the reasons behind this. == Locations Configured by Subrequest Directives of Other Modules == The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] directives cannot capture locations that include the [[HttpEchoModule#echo_location|echo_location]], [[HttpEchoModule#echo_location_async|echo_location_async]], [[HttpEchoModule#echo_subrequest|echo_subrequest]], or [[HttpEchoModule#echo_subrequest_async|echo_subrequest_async]] directives. From db35efd18d30ad427f44c90bf2b1f6cd8df17a41 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 19 Sep 2013 12:27:05 -0700 Subject: [PATCH 0239/1981] docs: documented more limitations in the current implementation. --- README | 13 +++++++++++++ README.markdown | 12 ++++++++++++ doc/HttpLuaModule.wiki | 10 ++++++++++ 3 files changed, 35 insertions(+) diff --git a/README b/README index fa8e5015c3..0fdb0a2321 100644 --- a/README +++ b/README @@ -2964,6 +2964,8 @@ Nginx API for Lua header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. + Chunked request bodies are not yet supported in this API. + This function was first introduced in the "v0.5.0rc1" release. ngx.exec @@ -5928,6 +5930,17 @@ Known Issues if m then ngx.say(m[0]) else ngx.say("not matched!") end -- evaluates to "1234" + Mixing with SSI Not Supported + Mixing SSI with ngx_lua in the same Nginx request is not supported at + all. Just use ngx_lua exclusively. Everything you can do with SSI can be + done atop ngx_lua anyway and it can be more efficient when using + ngx_lua. + + SPDY Mode Not Fully Supported + Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode + yet: ngx.location.capture, ngx.location.capture_multi, and + ngx.req.socket. + Typical Uses Just to name a few: diff --git a/README.markdown b/README.markdown index b9fbb968a0..9e1149faaf 100644 --- a/README.markdown +++ b/README.markdown @@ -2720,6 +2720,8 @@ The socket object returned by this method is usually used to read the current re If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. +Chunked request bodies are not yet supported in this API. + This function was first introduced in the `v0.5.0rc1` release. ngx.exec @@ -5263,6 +5265,16 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" +Mixing with SSI Not Supported +----------------------------- + +Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. + +SPDY Mode Not Fully Supported +----------------------------- + +Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture), [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi), and [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket). + Typical Uses ============ diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 8e4474db71..36789d45ea 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2636,6 +2636,8 @@ The socket object returned by this method is usually used to read the current re If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. +Chunked request bodies are not yet supported in this API. + This function was first introduced in the v0.5.0rc1 release. == ngx.exec == @@ -5089,6 +5091,14 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" +== Mixing with SSI Not Supported == + +Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. + +== SPDY Mode Not Fully Supported == + +Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], and [[#ngx.req.socket|ngx.req.socket]]. + = Typical Uses = Just to name a few: From 1d4c76d172142a4df2cf4eb4e86db0d15812f2d7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 22 Sep 2013 14:22:41 -0700 Subject: [PATCH 0240/1981] bugfix: we did not declare the "level" local variable of ngx_http_lua_ngx_log at the beginning of the code block. thanks Edwin Cleton for the report. --- src/ngx_http_lua_log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index 850b2f99b7..daca3fd3a5 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -35,6 +35,7 @@ ngx_http_lua_ngx_log(lua_State *L) ngx_log_t *log; ngx_http_request_t *r; const char *msg; + int level; r = ngx_http_lua_get_req(L); @@ -45,7 +46,7 @@ ngx_http_lua_ngx_log(lua_State *L) log = ngx_cycle->log; } - int level = luaL_checkint(L, 1); + level = luaL_checkint(L, 1); if (level < NGX_LOG_STDERR || level > NGX_LOG_DEBUG) { msg = lua_pushfstring(L, "bad log level: %d", level); return luaL_argerror(L, 1, msg); From e78dea9e0f3039d04a6b21bc43525f0689a9a5bc Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 22 Sep 2013 14:52:32 -0700 Subject: [PATCH 0241/1981] bumped version to 0.8.10. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 0fdb0a2321..1f9f9c5b11 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.9 - () released on 15 + This document describes ngx_lua v0.8.10 + () released on 22 September 2013. Synopsis diff --git a/README.markdown b/README.markdown index 9e1149faaf..d8f86baeac 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 15 September 2013. +This document describes ngx_lua [v0.8.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 September 2013. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 36789d45ea..ad1f64f470 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.9] released on 15 September 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.10] released on 22 September 2013. = Synopsis = From a0ff1922184e6257aa348e3c1c5bfe45aecf3b07 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 22 Sep 2013 20:47:56 -0700 Subject: [PATCH 0242/1981] bugfix: memory invalid reads might happen when ngx.flush(true) was used: the "ctx" struct could get freed in the middle of processing and we should save the state explicitly on the C stack. --- src/ngx_http_lua_util.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index d264fd5b63..73602ec7e9 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1616,17 +1616,21 @@ static ngx_int_t ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { - ngx_int_t rc; + ngx_int_t rc, n; ngx_uint_t i; ngx_list_part_t *part; ngx_http_lua_co_ctx_t *coctx; + dd("processing flushing coroutines"); + coctx = &ctx->entry_co_ctx; + n = ctx->flushing_coros; if (coctx->flushing) { coctx->flushing = 0; ctx->flushing_coros--; + n--; ctx->cur_co_ctx = coctx; rc = ngx_http_lua_flush_resume_helper(r, ctx); @@ -1637,7 +1641,7 @@ ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, /* rc == NGX_DONE */ } - if (ctx->flushing_coros) { + if (n) { if (ctx->user_co_ctx == NULL) { return NGX_ERROR; @@ -1669,14 +1673,16 @@ ngx_http_lua_process_flushing_coroutines(ngx_http_request_t *r, /* rc == NGX_DONE */ - if (--ctx->flushing_coros == 0) { - break; + ctx->flushing_coros--; + n--; + if (n == 0) { + return NGX_DONE; } } } } - if (ctx->flushing_coros) { + if (n) { return NGX_ERROR; } From 33832b1f7a44921b3534c408392030e14148ac89 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 23 Sep 2013 00:10:09 -0700 Subject: [PATCH 0243/1981] fixed bad request header lines in the tests in 116-raw-req-socket.t, which caused test bailout in the "check leak" testing mode. --- t/116-raw-req-socket.t | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index 3b7d7a4b1e..92f8a74802 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -125,7 +125,7 @@ lua raw req socket tcp_nodelay --- raw_request eval "GET /t HTTP/1.0\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- ignore_response @@ -152,7 +152,7 @@ server: failed to get raw req socket: response header not sent yet --- raw_request eval "GET /t HTTP/1.0\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- stap2 @@ -193,7 +193,7 @@ server: failed to get raw req socket: http 1.0 buffering --- raw_request eval "GET /t HTTP/1.1\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- stap2 @@ -233,7 +233,7 @@ server: failed to get raw req socket2: duplicate call --- raw_request eval "GET /t HTTP/1.1\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- ignore_response @@ -266,7 +266,7 @@ failed to say: raw request socket acquired --- raw_request eval "GET /t HTTP/1.1\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- ignore_response @@ -299,7 +299,7 @@ failed to print: raw request socket acquired --- raw_request eval "GET /t HTTP/1.1\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- ignore_response @@ -332,7 +332,7 @@ failed to eof: raw request socket acquired --- raw_request eval "GET /t HTTP/1.1\r Host: localhost\r -Upgrade: mysocket +Upgrade: mysocket\r \r hello" --- ignore_response From 585e7af92ef8f6bee22848bcdd8b269d190d8836 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 23 Sep 2013 20:22:48 -0700 Subject: [PATCH 0244/1981] bugfix: fixed most of the compiler warnings from the MinGW C compiler, some of which are real overflow issues. thanks Edwin Cleton for the report. --- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_common.h | 4 ++-- src/ngx_http_lua_directive.c | 14 +++++++------- src/ngx_http_lua_exception.c | 3 +-- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_module.c | 32 +++++++++++++++---------------- src/ngx_http_lua_ndk.c | 2 +- src/ngx_http_lua_output.c | 2 +- src/ngx_http_lua_regex.c | 12 ++++++------ src/ngx_http_lua_req_body.c | 4 ++-- src/ngx_http_lua_shdict.c | 16 ++++++++-------- src/ngx_http_lua_sleep.c | 2 +- src/ngx_http_lua_socket_tcp.c | 20 +++++++++---------- src/ngx_http_lua_socket_udp.c | 2 +- src/ngx_http_lua_subrequest.c | 2 +- src/ngx_http_lua_timer.c | 9 +++++---- src/ngx_http_lua_util.c | 8 ++++---- src/ngx_http_lua_util.h | 2 +- 18 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 7432a5f5e6..fa55e68c41 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -242,7 +242,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; - uint8_t old_context; + uint16_t old_context; ngx_http_cleanup_t *cln; ngx_http_lua_main_conf_t *lmcf; lua_State *L; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index a170f23b04..b03d7bb994 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -272,7 +272,7 @@ struct ngx_http_lua_co_ctx_s { unsigned waited_by_parent:1; /* whether being waited by a parent coroutine */ - ngx_http_lua_co_status_t co_status:3; /* the current coroutine's status */ + unsigned co_status:3; /* the current coroutine's status */ unsigned flushing:1; /* indicates whether the current coroutine is waiting for @@ -351,7 +351,7 @@ typedef struct ngx_http_lua_ctx_s { request body data; 0: no need to wait */ - ngx_http_lua_user_coro_op_t co_op:2; /* coroutine API operation */ + unsigned co_op:2; /* coroutine API operation */ unsigned exited:1; diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 7ca72ee354..ba4c9c8833 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -442,7 +442,7 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - llcf->rewrite_handler = cmd->post; + llcf->rewrite_handler = (ngx_http_handler_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -524,7 +524,7 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - llcf->access_handler = cmd->post; + llcf->access_handler = (ngx_http_handler_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -606,7 +606,7 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - llcf->content_handler = cmd->post; + llcf->content_handler = (ngx_http_handler_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -695,7 +695,7 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - llcf->log_handler = cmd->post; + llcf->log_handler = (ngx_http_handler_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -776,7 +776,7 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } } - llcf->header_filter_handler = cmd->post; + llcf->header_filter_handler = (ngx_http_handler_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -857,7 +857,7 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, } } - llcf->body_filter_handler = cmd->post; + llcf->body_filter_handler = (ngx_http_output_body_filter_pt) cmd->post; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); @@ -896,7 +896,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - lmcf->init_handler = cmd->post; + lmcf->init_handler = (ngx_http_lua_conf_handler_pt) cmd->post; if (cmd->post == ngx_http_lua_init_by_file) { name = ngx_http_lua_rebase_path(cf->pool, value[1].data, diff --git a/src/ngx_http_lua_exception.c b/src/ngx_http_lua_exception.c index 92ed57a8f2..014aba444b 100644 --- a/src/ngx_http_lua_exception.c +++ b/src/ngx_http_lua_exception.c @@ -31,7 +31,7 @@ int ngx_http_lua_atpanic(lua_State *L) { u_char *s = NULL; - size_t len; + size_t len = 0; if (lua_type(L, -1) == LUA_TSTRING) { s = (u_char *) lua_tolstring(L, -1, &len); @@ -49,7 +49,6 @@ ngx_http_lua_atpanic(lua_State *L) NGX_LUA_EXCEPTION_THROW(1); /* impossible to reach here */ - return 0; } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index bf53c4824b..0f62166e03 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -230,7 +230,7 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_http_cleanup_t *cln; - uint8_t old_context; + uint16_t old_context; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua header filter for user lua code, uri \"%V\"", &r->uri); diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 2f3ecdfb42..bcc80a09a7 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -135,14 +135,14 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_init_by_lua, NGX_HTTP_MAIN_CONF_OFFSET, 0, - ngx_http_lua_init_by_inline }, + (void *) ngx_http_lua_init_by_inline }, { ngx_string("init_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_http_lua_init_by_lua, NGX_HTTP_MAIN_CONF_OFFSET, 0, - ngx_http_lua_init_by_file }, + (void *) ngx_http_lua_init_by_file }, #if defined(NDK) && NDK /* set_by_lua $res [$arg1 [$arg2 [...]]] */ @@ -152,7 +152,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_set_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_filter_set_by_lua_inline }, + (void *) ngx_http_lua_filter_set_by_lua_inline }, /* set_by_lua_file $res rel/or/abs/path/to/script [$arg1 [$arg2 [..]]] */ { ngx_string("set_by_lua_file"), @@ -161,7 +161,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_set_by_lua_file, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_filter_set_by_lua_file }, + (void *) ngx_http_lua_filter_set_by_lua_file }, #endif /* rewrite_by_lua */ @@ -171,7 +171,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_rewrite_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_rewrite_handler_inline }, + (void *) ngx_http_lua_rewrite_handler_inline }, /* access_by_lua */ { ngx_string("access_by_lua"), @@ -180,7 +180,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_access_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_access_handler_inline }, + (void *) ngx_http_lua_access_handler_inline }, /* content_by_lua */ { ngx_string("content_by_lua"), @@ -188,7 +188,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_content_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_content_handler_inline }, + (void *) ngx_http_lua_content_handler_inline }, /* log_by_lua */ { ngx_string("log_by_lua"), @@ -197,7 +197,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_log_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_log_handler_inline }, + (void *) ngx_http_lua_log_handler_inline }, { ngx_string("rewrite_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -205,7 +205,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_rewrite_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_rewrite_handler_file }, + (void *) ngx_http_lua_rewrite_handler_file }, { ngx_string("rewrite_by_lua_no_postpone"), NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, @@ -220,7 +220,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_access_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_access_handler_file }, + (void *) ngx_http_lua_access_handler_file }, /* content_by_lua_file rel/or/abs/path/to/script */ { ngx_string("content_by_lua_file"), @@ -228,7 +228,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_content_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_content_handler_file }, + (void *) ngx_http_lua_content_handler_file }, { ngx_string("log_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -236,7 +236,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_log_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_log_handler_file }, + (void *) ngx_http_lua_log_handler_file }, /* header_filter_by_lua */ { ngx_string("header_filter_by_lua"), @@ -245,7 +245,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_header_filter_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_header_filter_inline }, + (void *) ngx_http_lua_header_filter_inline }, { ngx_string("header_filter_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -253,7 +253,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_header_filter_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_header_filter_file }, + (void *) ngx_http_lua_header_filter_file }, { ngx_string("body_filter_by_lua"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -261,7 +261,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_body_filter_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_body_filter_inline }, + (void *) ngx_http_lua_body_filter_inline }, { ngx_string("body_filter_by_lua_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF @@ -269,7 +269,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_lua_body_filter_by_lua, NGX_HTTP_LOC_CONF_OFFSET, 0, - ngx_http_lua_body_filter_file }, + (void *) ngx_http_lua_body_filter_file }, { ngx_string("lua_socket_keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF diff --git a/src/ngx_http_lua_ndk.c b/src/ngx_http_lua_ndk.c index c7306a31da..d942296d23 100644 --- a/src/ngx_http_lua_ndk.c +++ b/src/ngx_http_lua_ndk.c @@ -44,7 +44,7 @@ ngx_http_lua_ndk_set_var_get(lua_State *L) lua_pushvalue(L, -1); /* table key key */ lua_pushvalue(L, -1); /* table key key key */ - lua_pushlightuserdata(L, func); /* table key key key func */ + lua_pushlightuserdata(L, (void *) func); /* table key key key func */ lua_pushcclosure(L, ngx_http_lua_run_set_var_directive, 2); /* table key key closure */ lua_rawset(L, 1); /* table key */ diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 42f54fc769..99e4e72f20 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -285,7 +285,7 @@ ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, if (floor(key) == key && key >= 1) { if (key > max) { - max = key; + max = (int) key; } lua_pop(L, 1); /* stack: table key */ diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index bd385643cb..fa9246f410 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -127,8 +127,8 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_http_lua_main_conf_t *lmcf; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; - int name_entry_size, name_count; - u_char *name_table; + int name_entry_size = 0, name_count; + u_char *name_table = NULL; int exec_opts; ngx_http_lua_regex_compile_t re_comp; @@ -896,8 +896,8 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) ngx_str_t subj; int offset; const char *msg = NULL; - int name_entry_size, name_count; - u_char *name_table; + int name_entry_size = 0, name_count; + u_char *name_table = NULL; int exec_opts; /* upvalues in order: subj ctx offset */ @@ -1204,8 +1204,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) u_char *p; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; - int name_entry_size, name_count; - u_char *name_table; + int name_entry_size = 0, name_count; + u_char *name_table = NULL; int exec_opts; ngx_http_lua_regex_compile_t re_comp; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index c31ef765a3..d2f3365c51 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -558,7 +558,7 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) /* avoid allocating an unnecessary large buffer */ if (size > (size_t) r->headers_in.content_length_n) { - size = r->headers_in.content_length_n; + size = (size_t) r->headers_in.content_length_n; } } @@ -738,7 +738,7 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) return luaL_error(L, "out of memory"); } - size = r->headers_in.content_length_n; + size = (size_t) r->headers_in.content_length_n; value.len = ngx_sprintf(value.data, "%uz", size) - value.data; value.data[value.len] = '\0'; diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 7e2f04aa77..4837813130 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -618,7 +618,7 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) } if (n == 2) { - attempts = luaL_checknumber(L, 2); + attempts = luaL_checkint(L, 2); } ctx = zone->data; @@ -699,7 +699,7 @@ ngx_http_lua_shdict_get_keys(lua_State *L) } if (n == 2) { - attempts = luaL_checknumber(L, 2); + attempts = luaL_checkint(L, 2); } ctx = zone->data; @@ -969,12 +969,12 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); - sd->key_len = key.len; + sd->key_len = (ushort) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + exptime * 1000; + + (uint64_t) (exptime * 1000); } else { sd->expires = 0; @@ -986,7 +986,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) dd("setting value type to %d", value_type); - sd->value_type = value_type; + sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); @@ -1076,12 +1076,12 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; - sd->key_len = key.len; + sd->key_len = (ushort) key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + exptime * 1000; + + (uint64_t) (exptime * 1000); } else { sd->expires = 0; @@ -1093,7 +1093,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) dd("setting value type to %d", value_type); - sd->value_type = value_type; + sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 997d9646d5..0660da7bb2 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -41,7 +41,7 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "no request found"); } - delay = luaL_checknumber(L, 1) * 1000; + delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000); if (delay < 0) { return luaL_error(L, "invalid sleep duration \"%d\"", delay); diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index abf124a71d..2f57251dea 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -488,7 +488,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) url.url.len = host.len; url.url.data = host.data; - url.default_port = port; + url.default_port = (in_port_t) port; url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { @@ -1377,7 +1377,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, size_t size; ssize_t n; unsigned read; - size_t preread = 0; + off_t preread = 0; ngx_http_lua_loc_conf_t *llcf; c = u->peer.connection; @@ -1479,7 +1479,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, } b = &u->buffer; - size = b->end - b->last; + size = (size_t) (b->end - b->last); } if (u->raw_downstream) { @@ -1487,8 +1487,8 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (preread) { - if (size > preread) { - size = preread; + if ((off_t) size > preread) { + size = (size_t) preread; } ngx_http_lua_probe_req_socket_consume_preread(r, @@ -1523,14 +1523,14 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http client request body preread %uz", preread); + "http client request body preread %O", preread); - if ((off_t) preread >= r->request_body->rest) { + if (preread >= r->request_body->rest) { preread = r->request_body->rest; } - if (size > preread) { - size = preread; + if ((off_t) size > preread) { + size = (size_t) preread; } ngx_http_lua_probe_req_socket_consume_preread(r, @@ -2780,7 +2780,7 @@ ngx_http_lua_socket_compile_pattern(u_char *data, size_t len, int cur_state, new_state; ngx_http_lua_dfa_edge_t *edge; - ngx_http_lua_dfa_edge_t **last; + ngx_http_lua_dfa_edge_t **last = NULL; cp->pattern.len = len; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 2a73818648..1dc9f0898d 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -285,7 +285,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) url.url.len = host.len; url.url.data = host.data; - url.default_port = port; + url.default_port = (in_port_t) port; url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 3bba4726cd..6c8ad9ff52 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1368,7 +1368,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, { lua_pushliteral(co, "Content-Length"); /* header key */ - lua_pushnumber(co, sr_headers->content_length_n); + lua_pushnumber(co, (lua_Number) sr_headers->content_length_n); /* head key value */ lua_rawset(co, -3); /* head */ diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 079a90ffff..6a44df010a 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -120,8 +120,9 @@ ngx_http_lua_ngx_timer_at(lua_State *L) return luaL_error(L, "no memory"); } - lmcf->watcher->fd = -2; /* to work around the -1 check in - ngx_worker_process_cycle */ + /* to work around the -1 check in ngx_worker_process_cycle: */ + lmcf->watcher->fd = (ngx_socket_t) -2; + lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; @@ -282,7 +283,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) goto abort; } - c->fd = -1; + c->fd = (ngx_socket_t) -1; c->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); if (c->pool == NULL) { @@ -543,7 +544,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) ngx_free_connection(c); - c->fd = -1; + c->fd = (ngx_socket_t) -1; if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 73602ec7e9..0c9026f7d7 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -657,7 +657,7 @@ static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { - size_t size; + off_t size; ngx_chain_t *cl; ngx_int_t rc; @@ -677,7 +677,7 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, size += ngx_buf_size(cl->buf); } - r->headers_out.content_length_n = (off_t) size; + r->headers_out.content_length_n = size; if (r->headers_out.content_length) { r->headers_out.content_length->hash = 0; @@ -3053,7 +3053,7 @@ ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, return rc; } - return NGX_DONE; + /* impossible to reach here */ } @@ -3575,7 +3575,7 @@ ngx_http_lua_close_fake_connection(ngx_connection_t *c) ngx_free_connection(c); - c->fd = -1; + c->fd = (ngx_socket_t) -1; if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index a5648c652b..5df9040e69 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -109,7 +109,7 @@ void ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int foricible); void ngx_http_lua_request_cleanup_handler(void *data); ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int nret); + ngx_http_lua_ctx_t *ctx, volatile int nret); ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r); From c6b6b315dfa0939a740ccefbdcad20a4c84856c8 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 24 Sep 2013 14:21:45 -0700 Subject: [PATCH 0245/1981] more warning fixes for the Microsoft Visual C++ compiler. thanks Edwin Cleton for the report. --- src/ngx_http_lua_control.c | 4 +--- src/ngx_http_lua_headers_out.c | 10 ++-------- src/ngx_http_lua_module.c | 5 +++++ src/ngx_http_lua_output.c | 2 +- src/ngx_http_lua_shdict.c | 4 ++-- src/ngx_http_lua_subrequest.c | 5 +---- src/ngx_http_lua_util.c | 4 ++++ src/ngx_http_lua_util.h | 24 ++++++++++++++++++++++++ t/022-redirect.t | 2 +- 9 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index e14ab529e2..c5d2a5932b 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -253,9 +253,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) return luaL_error(L, "out of memory"); } - r->headers_out.location->hash = - ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); + r->headers_out.location->hash = ngx_http_lua_location_hash; #if 0 dd("location hash: %lu == %lu", diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 29bfc46fc7..2ee10d1ffb 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -142,10 +142,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, * for a nasty optimization purpose, and * we have to work-around it here */ - r->headers_out.location->hash = - ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); - + r->headers_out.location->hash = ngx_http_lua_location_hash; ngx_str_set(&r->headers_out.location->key, "Location"); } #endif @@ -533,10 +530,7 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, * for a nasty optimization purpose, and * we have to work-around it here */ - r->headers_out.location->hash = - ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); - + r->headers_out.location->hash = ngx_http_lua_location_hash; ngx_str_set(&r->headers_out.location->key, "Location"); } #endif diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index bcc80a09a7..163f6d64e2 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -731,6 +731,11 @@ ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) lua_State *L; ngx_uint_t i; + ngx_http_lua_content_length_hash = + ngx_http_lua_hash_literal("content-length"); + + ngx_http_lua_location_hash = ngx_http_lua_hash_literal("location"); + /* add new cleanup handler to config mem pool */ cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 99e4e72f20..dab007799c 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -392,7 +392,7 @@ ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst) while (lua_next(L, index) != 0) { /* stack: table key value */ key = lua_tonumber(L, -2); if (key > max) { - max = key; + max = (int) key; } lua_pop(L, 1); /* stack: table key */ diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 4837813130..76e89aa82c 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -969,7 +969,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); - sd->key_len = (ushort) key.len; + sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); @@ -1076,7 +1076,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; - sd->key_len = (ushort) key.len; + sd->key_len = (u_short) key.len; if (exptime > 0) { tp = ngx_timeofday(); diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 6c8ad9ff52..bb10fff4b0 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1153,10 +1153,7 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data; - h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash('c', 'o'), 'n'), 't'), 'e'), 'n'), 't'), '-'), 'l'), 'e'), - 'n'), 'g'), 't'), 'h'); + h->hash = ngx_http_lua_content_length_hash; #if 0 dd("content length hash: %lu == %lu", (unsigned long) h->hash, diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0c9026f7d7..481f95a135 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -73,6 +73,10 @@ char ngx_http_lua_coroutines_key; char ngx_http_lua_req_get_headers_metatable_key; +ngx_uint_t ngx_http_lua_location_hash = 0; +ngx_uint_t ngx_http_lua_content_length_hash = 0; + + static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static void ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 5df9040e69..72855692cc 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -229,6 +229,30 @@ ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) } +#define ngx_http_lua_hash_literal(s) \ + ngx_http_lua_hash_str((u_char *) s, sizeof(s) - 1) + + +static ngx_inline ngx_uint_t +ngx_http_lua_hash_str(u_char *src, size_t n) +{ + ngx_uint_t key; + + key = 0; + + while (n--) { + key = ngx_hash(key, *src); + src++; + } + + return key; +} + + +extern ngx_uint_t ngx_http_lua_location_hash; +extern ngx_uint_t ngx_http_lua_content_length_hash; + + #endif /* _NGX_HTTP_LUA_UTIL_H_INCLUDED_ */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/022-redirect.t b/t/022-redirect.t index d2564b87d5..895ed23e6f 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -7,7 +7,7 @@ use t::TestNginxLua; #master_process_enabled(1); #log_level('warn'); -#repeat_each(2); +repeat_each(2); #repeat_each(1); plan tests => repeat_each() * (blocks() * 3 + 1); From a41567b64c72d9e65df1beb7942f8d545a37d3d1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 24 Sep 2013 23:25:59 -0700 Subject: [PATCH 0246/1981] bugfix: the standard Lua coroutine API was not available in the context of init_by_lua* and threw out the "no request found" error. thanks Wolf Tivy for the report. --- src/ngx_http_lua_coroutine.c | 12 ++++ src/ngx_http_lua_initby.c | 44 ++++++++++++++ t/086-init-by.t | 79 ++++++++++++++++++++++++- t/091-coroutine.t | 111 +++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 10c971086f..85c30b542d 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -234,6 +234,18 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) lua_getfield(L, -1, "running"); lua_setfield(L, -3, "running"); + lua_getfield(L, -1, "create"); + lua_setfield(L, -3, "_create"); + + lua_getfield(L, -1, "resume"); + lua_setfield(L, -3, "_resume"); + + lua_getfield(L, -1, "yield"); + lua_setfield(L, -3, "_yield"); + + lua_getfield(L, -1, "status"); + lua_setfield(L, -3, "_status"); + /* pop the old coroutine */ lua_pop(L, 1); diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index 72b705648b..701ec01112 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -15,6 +15,7 @@ static int ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status); static int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L); +static int ngx_http_lua_swap_coroutine_api(ngx_log_t *log, lua_State *L); int @@ -23,10 +24,22 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, { int status; + status = ngx_http_lua_swap_coroutine_api(log, L); + if (status != 0) { + goto done; + } + status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, lmcf->init_src.len, "init_by_lua") || ngx_http_lua_do_call(log, L); + if (status != 0) { + goto done; + } + + status = ngx_http_lua_swap_coroutine_api(log, L); + +done: return ngx_http_lua_report(log, L, status); } @@ -37,9 +50,21 @@ ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, { int status; + status = ngx_http_lua_swap_coroutine_api(log, L); + if (status != 0) { + goto done; + } + status = luaL_loadfile(L, (char *) lmcf->init_src.data) || ngx_http_lua_do_call(log, L); + if (status != 0) { + goto done; + } + + status = ngx_http_lua_swap_coroutine_api(log, L); + +done: return ngx_http_lua_report(log, L, status); } @@ -81,4 +106,23 @@ ngx_http_lua_do_call(ngx_log_t *log, lua_State *L) return status; } + +static int +ngx_http_lua_swap_coroutine_api(ngx_log_t *log, lua_State *L) +{ + const char code[] = "do\n" + "local keys = {'create', 'yield', 'resume', 'status'}" + "for _, key in ipairs(keys) do\n" + "local _key = '_' .. key\n" + "local f = coroutine[_key]\n" + "coroutine[_key] = coroutine[key]\n" + "coroutine[key] = f\n" + "end\n" + "end"; + + return luaL_loadbuffer(L, code, sizeof(code) - 1, "swap coroutine api") + || ngx_http_lua_do_call(log, L); +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/086-init-by.t b/t/086-init-by.t index b22771e2a6..13f1c6e0eb 100644 --- a/t/086-init-by.t +++ b/t/086-init-by.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -197,3 +197,80 @@ hello, blah --- no_error_log [error] + + +=== TEST 9: coroutine API (inlined init_by_lua) +--- http_config + init_by_lua ' + local function f() + foo = 32 + coroutine.yield(78) + bar = coroutine.status(coroutine.running()) + end + local co = coroutine.create(f) + local ok, err = coroutine.resume(co) + if not ok then + print("Failed to resume our co: ", err) + return + end + baz = err + coroutine.resume(co) + '; +--- config + location /lua { + content_by_lua ' + ngx.say("foo = ", foo) + ngx.say("bar = ", bar) + ngx.say("baz = ", baz) + '; + } +--- request +GET /lua +--- response_body +foo = 32 +bar = running +baz = 78 +--- no_error_log +[error] +Failed to resume our co: + + + +=== TEST 10: coroutine API (init_by_lua_file) +--- http_config + init_by_lua_file html/init.lua; + +--- config + location /lua { + content_by_lua ' + ngx.say("foo = ", foo) + ngx.say("bar = ", bar) + ngx.say("baz = ", baz) + '; + } +--- request +GET /lua +--- user_files +>>> init.lua +local function f() + foo = 32 + coroutine.yield(78) + bar = coroutine.status(coroutine.running()) +end +local co = coroutine.create(f) +local ok, err = coroutine.resume(co) +if not ok then + print("Failed to resume our co: ", err) + return +end +baz = err +coroutine.resume(co) + +--- response_body +foo = 32 +bar = running +baz = 78 +--- no_error_log +[error] +Failed to resume our co: + diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 4dc4c21217..931954f7a6 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -980,3 +980,114 @@ test10 --- no_error_log [error] + + +=== TEST 24: init_by_lua + our own coroutines in content_by_lua +--- http_config + init_by_lua return; +--- config + resolver $TEST_NGINX_RESOLVER; + location /lua { + content_by_lua ' + function worker(url) + local sock = ngx.socket.tcp() + local ok, err = sock:connect(url, 80) + coroutine.yield() + if not ok then + ngx.say("failed to connect to: ", url, " error: ", err) + return + end + coroutine.yield() + ngx.say("successfully connected to: ", url) + sock:close() + end + + local urls = { + "agentzh.org", + } + + local ccs = {} + for i, url in ipairs(urls) do + local cc = coroutine.create(function() worker(url) end) + ccs[#ccs+1] = cc + end + + while true do + if #ccs == 0 then break end + local cc = table.remove(ccs, 1) + local ok = coroutine.resume(cc) + if ok then + ccs[#ccs+1] = cc + end + end + + ngx.say("*** All Done ***") + '; + } +--- request +GET /lua +--- response_body +successfully connected to: agentzh.org +*** All Done *** +--- no_error_log +[error] +--- timeout: 10 + + + +=== TEST 25: init_by_lua_file + our own coroutines in content_by_lua +--- http_config + init_by_lua_file html/init.lua; + +--- config + resolver $TEST_NGINX_RESOLVER; + location /lua { + content_by_lua ' + function worker(url) + local sock = ngx.socket.tcp() + local ok, err = sock:connect(url, 80) + coroutine.yield() + if not ok then + ngx.say("failed to connect to: ", url, " error: ", err) + return + end + coroutine.yield() + ngx.say("successfully connected to: ", url) + sock:close() + end + + local urls = { + "agentzh.org" + } + + local ccs = {} + for i, url in ipairs(urls) do + local cc = coroutine.create(function() worker(url) end) + ccs[#ccs+1] = cc + end + + while true do + if #ccs == 0 then break end + local cc = table.remove(ccs, 1) + local ok = coroutine.resume(cc) + if ok then + ccs[#ccs+1] = cc + end + end + + ngx.say("*** All Done ***") + '; + } +--- user_files +>>> init.lua +return + +--- request +GET /lua +--- response_body +successfully connected to: agentzh.org +*** All Done *** +--- no_error_log +[error] +--- timeout: 10 + From 0387a89e7cdb9f240688d234f44d89134538f6e5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 12:24:05 -0700 Subject: [PATCH 0247/1981] bugfix: Windows compatibility issue in the Lua/LuaJIT bytecode file loader: it assumed that ngx_fd_info accepts integral fd as the 1st argument. thanks Edwin Cleton for the report (#283) and thanks jinglong for the original patch in #284. --- src/ngx_http_lua_clfactory.c | 38 ++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 778bb22d69..c5c3ed36f1 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -293,6 +293,7 @@ static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index); static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size); +static long ngx_http_lua_clfactory_file_size(FILE *f); int @@ -304,7 +305,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, static int num_of_inst = 3, num_of_inter_func = 1; const char *filename, *emsg, *serr, *bytecode; size_t size, bytecode_len; - ngx_file_info_t fi; + long fsize; serr = NULL; @@ -365,13 +366,14 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, lf->end_code_len = LJ_CODE_LEN; } - if (ngx_fd_info(fileno(lf->f), &fi) == NGX_FILE_ERROR) { + fsize = ngx_http_lua_clfactory_file_size(lf->f); + if (fsize < 0) { serr = strerror(errno); - emsg = "cannot fstat"; + emsg = "cannot fseek/ftell"; goto error; } - lf->rest_len = ngx_file_size(&fi) - LJ_HEADERSIZE; + lf->rest_len = fsize - LJ_HEADERSIZE; #if defined(DDEBUG) && (DDEBUG) { @@ -791,4 +793,32 @@ ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size) return ls->s; } + +static long +ngx_http_lua_clfactory_file_size(FILE *f) +{ + long cur_pos, len; + + cur_pos = ftell(f); + if (cur_pos == -1) { + return -1; + } + + if (fseek(f, 0, SEEK_END) != 0) { + return -1; + } + + len = ftell(f); + if (len == -1) { + return -1; + } + + if (fseek(f, cur_pos, SEEK_SET) != 0) { + return -1; + } + + return len; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 095ed4a235fc04451383331fc193f51508d964fc Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 13:37:36 -0700 Subject: [PATCH 0248/1981] bugfix: compilation regressions with nginx older than 1.3.13, introduced recently by the ngx.req.socket(true) API. --- src/ngx_http_lua_socket_tcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 2f57251dea..4d25ef83c5 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3082,7 +3082,7 @@ ngx_http_lua_socket_cleanup_compiled_pattern(lua_State *L) static int ngx_http_lua_req_socket(lua_State *L) { - int n, raw, tcp_nodelay; + int n, raw; ngx_peer_connection_t *pc; ngx_http_lua_loc_conf_t *llcf; ngx_connection_t *c; @@ -3091,7 +3091,10 @@ ngx_http_lua_req_socket(lua_State *L) ngx_http_request_body_t *rb; ngx_http_cleanup_t *cln; ngx_http_lua_co_ctx_t *coctx; +#if nginx_version >= 1003013 + int tcp_nodelay; ngx_http_core_loc_conf_t *clcf; +#endif ngx_http_lua_socket_tcp_upstream_t *u; From 5dfd547141ba00f4e73f0544a511a53b5982030d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 14:58:43 -0700 Subject: [PATCH 0249/1981] tests: removed the "single" option from the "keepalive" directive because it is not a public feature. --- t/005-exit.t | 2 +- t/023-rewrite/exit.t | 2 +- t/024-access/exit.t | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/005-exit.t b/t/005-exit.t index 24806b6d62..abfa78895a 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -360,7 +360,7 @@ Logged in 56 upstream memc_a { server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - keepalive 300 single; + keepalive 300; } #upstream_list memc_cluster memc_a memc_b; diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index 67b5d4bf17..32de65f987 100644 --- a/t/023-rewrite/exit.t +++ b/t/023-rewrite/exit.t @@ -356,7 +356,7 @@ Logged in 56 upstream memc_a { server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - keepalive 300 single; + keepalive 300; } #upstream_list memc_cluster memc_a memc_b; diff --git a/t/024-access/exit.t b/t/024-access/exit.t index 4083e090b1..0753c405a1 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -334,7 +334,7 @@ Logged in 56 upstream memc_a { server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - keepalive 300 single; + keepalive 300; } #upstream_list memc_cluster memc_a memc_b; From 7720bc7d9dce44e3fa51fbe3b5229186814e882e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 14:59:20 -0700 Subject: [PATCH 0250/1981] removed the ngx_upstream_keepalive module from the developer build script because it has been included in the official nginx distribution. --- util/build2.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/util/build2.sh b/util/build2.sh index 8bc267911e..63b7d0bce1 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -41,7 +41,6 @@ time ngx-build $force $version \ --add-module=$root \ --add-module=$root/../headers-more-nginx-module \ --add-module=$root/../drizzle-nginx-module \ - --add-module=$home/work/nginx/ngx_http_upstream_keepalive-0.7 \ --add-module=$root/../rds-json-nginx-module \ --add-module=$root/../coolkit-nginx-module \ --add-module=$root/../redis2-nginx-module \ From 42567bd245948a77f8f0e6c484de3b809355cf85 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 15:03:52 -0700 Subject: [PATCH 0251/1981] docs: made the "Test Suite" section up to date (I hope). --- README | 87 ++++++++++++++++++++++-------------------- README.markdown | 74 +++++++++++++++++++---------------- doc/HttpLuaModule.wiki | 74 +++++++++++++++++++---------------- 3 files changed, 130 insertions(+), 105 deletions(-) diff --git a/README b/README index 1f9f9c5b11..08109ac422 100644 --- a/README +++ b/README @@ -6139,77 +6139,82 @@ Changes Test Suite The following dependencies are required to run the test suite: - * Nginx version >= 0.8.54 + * Nginx version >= 1.4.2 * Perl modules: - * test-nginx: http://github.com/agentzh/test-nginx + * Test::Nginx: http://github.com/agentzh/test-nginx * Nginx modules: - * echo-nginx-module: http://github.com/agentzh/echo-nginx-module + * ngx_devel_kit () - * drizzle-nginx-module: - http://github.com/chaoslawful/drizzle-nginx-module + * ngx_set_misc () - * rds-json-nginx-module: - http://github.com/agentzh/rds-json-nginx-module + * ngx_auth_request + () (this is not needed if you're using Nginx 1.5.4+. - * set-misc-nginx-module: - http://github.com/agentzh/set-misc-nginx-module + * ngx_echo () - * headers-more-nginx-module: - http://github.com/agentzh/headers-more-nginx-module + * ngx_memc () - * memc-nginx-module: http://github.com/agentzh/memc-nginx-module + * ngx_srcache () - * srcache-nginx-module: - http://github.com/agentzh/srcache-nginx-module + * ngx_lua (i.e., this module) - * ngx_auth_request: - http://mdounin.ru/hg/ngx_http_auth_request_module/ + * ngx_headers_more + () - * C libraries: + * ngx_drizzle + () - * yajl: https://github.com/lloyd/yajl + * ngx_rds_json () - * Lua modules: + * ngx_coolkit () - * lua-yajl: https://github.com/brimworks/lua-yajl + * ngx_redis2 () - * Note: the compiled module has to be placed in - '/usr/local/lib/lua/5.1/' + The order in which these modules are added during configuration is + important because the position of any filter module in the filtering + chain determines the final output, for example. The correct adding order + is shown above. + + * 3rd-party Lua libraries: + + * lua-cjson + () * Applications: * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' - * memcached - - The order in which these modules are added during configuration is - important as the position of any filter module in the filtering chain - determines the final output. The correct adding order is: - - 1. ngx_devel_kit - - 2. set-misc-nginx-module - - 3. ngx_http_auth_request_module - - 4. echo-nginx-module + * memcached: listening on the default port, 11211. - 5. memc-nginx-module + * redis: listening on the default port, 6379. - 6. lua-nginx-module (i.e. this module) + See also the developer build script + () for more details on setting up the testing environment. - 7. headers-more-nginx-module + To run the whole test suite in the default testing mode: cd + /path/to/lua-nginx-module export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib -r t - 8. srcache-nginx-module + To run specific test files: cd /path/to/lua-nginx-module export + PATH=/path/to/your/nginx/sbin:$PATH prove -I/path/to/test-nginx/lib + t/002-content.t t/003-errors.t - 9. drizzle-nginx-module + To run a specific test block in a particular test file, add the line + "--- ONLY" to the test block you want to run, and then use the `prove` + utility to run that ".t" file. - 10. rds-json-nginx-module + There are also various testing modes based on mockeagain, valgrind, and + etc. Refer to the Test::Nginx documentation + () for more details for + various advanced testing modes. See also the test reports for the Nginx + test cluster running on Amazon EC2: http://qa.openresty.org. Copyright and License This module is licensed under the BSD license. diff --git a/README.markdown b/README.markdown index d8f86baeac..b07b7baca3 100644 --- a/README.markdown +++ b/README.markdown @@ -5425,45 +5425,55 @@ Test Suite The following dependencies are required to run the test suite: -* Nginx version >= 0.8.54 +* Nginx version >= 1.4.2 * Perl modules: - * test-nginx: + * Test::Nginx: * Nginx modules: - * echo-nginx-module: - * drizzle-nginx-module: - * rds-json-nginx-module: - * set-misc-nginx-module: - * headers-more-nginx-module: - * memc-nginx-module: - * srcache-nginx-module: - * ngx_auth_request: - -* C libraries: - * yajl: - -* Lua modules: - * lua-yajl: - * Note: the compiled module has to be placed in '/usr/local/lib/lua/5.1/' + * [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) + * [ngx_set_misc](http://github.com/agentzh/set-misc-nginx-module) + * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. + * [ngx_echo](http://github.com/agentzh/echo-nginx-module) + * [ngx_memc](http://github.com/agentzh/memc-nginx-module) + * [ngx_srcache](http://github.com/agentzh/srcache-nginx-module) + * ngx_lua (i.e., this module) + * [ngx_headers_more](http://github.com/agentzh/headers-more-nginx-module) + * [ngx_drizzle](http://github.com/chaoslawful/drizzle-nginx-module) + * [ngx_rds_json](http://github.com/agentzh/rds-json-nginx-module) + * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) + * [ngx_redis2](http://github.com/agentzh/redis2-nginx-module) + +The order in which these modules are added during configuration is important because the position of any filter module in the +filtering chain determines the final output, for example. The correct adding order is shown above. + +* 3rd-party Lua libraries: + * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) * Applications: * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' - * memcached - -The order in which these modules are added during configuration is important as the position of any filter module in the -filtering chain determines the final output. The correct adding order is: - -1. ngx_devel_kit -1. set-misc-nginx-module -1. ngx_http_auth_request_module -1. echo-nginx-module -1. memc-nginx-module -1. lua-nginx-module (i.e. this module) -1. headers-more-nginx-module -1. srcache-nginx-module -1. drizzle-nginx-module -1. rds-json-nginx-module + * memcached: listening on the default port, 11211. + * redis: listening on the default port, 6379. + +See also the [developer build script](https://github.com/chaoslawful/lua-nginx-module/blob/master/util/build2.sh) for more details on setting up the testing environment. + +To run the whole test suite in the default testing mode: + + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib -r t + + +To run specific test files: + + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t + + +To run a specific test block in a particular test file, add the line `--- ONLY` to the test block you want to run, and then use the `prove` utility to run that `.t` file. + +There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [Test::Nginx documentation](http://search.cpan.org/perldoc?Test::Nginx) for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: Copyright and License ===================== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index ad1f64f470..4167789e00 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5235,45 +5235,55 @@ http://openresty.org/#Changes The following dependencies are required to run the test suite: -* Nginx version >= 0.8.54 +* Nginx version >= 1.4.2 * Perl modules: -** test-nginx: http://github.com/agentzh/test-nginx +** Test::Nginx: http://github.com/agentzh/test-nginx * Nginx modules: -** echo-nginx-module: http://github.com/agentzh/echo-nginx-module -** drizzle-nginx-module: http://github.com/chaoslawful/drizzle-nginx-module -** rds-json-nginx-module: http://github.com/agentzh/rds-json-nginx-module -** set-misc-nginx-module: http://github.com/agentzh/set-misc-nginx-module -** headers-more-nginx-module: http://github.com/agentzh/headers-more-nginx-module -** memc-nginx-module: http://github.com/agentzh/memc-nginx-module -** srcache-nginx-module: http://github.com/agentzh/srcache-nginx-module -** ngx_auth_request: http://mdounin.ru/hg/ngx_http_auth_request_module/ - -* C libraries: -** yajl: https://github.com/lloyd/yajl - -* Lua modules: -** lua-yajl: https://github.com/brimworks/lua-yajl -*** Note: the compiled module has to be placed in '/usr/local/lib/lua/5.1/' +** [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] +** [http://github.com/agentzh/set-misc-nginx-module ngx_set_misc] +** [http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz ngx_auth_request] (this is not needed if you're using Nginx 1.5.4+. +** [http://github.com/agentzh/echo-nginx-module ngx_echo] +** [http://github.com/agentzh/memc-nginx-module ngx_memc] +** [http://github.com/agentzh/srcache-nginx-module ngx_srcache] +** ngx_lua (i.e., this module) +** [http://github.com/agentzh/headers-more-nginx-module ngx_headers_more] +** [http://github.com/chaoslawful/drizzle-nginx-module ngx_drizzle] +** [http://github.com/agentzh/rds-json-nginx-module ngx_rds_json] +** [https://github.com/FRiCKLE/ngx_coolkit ngx_coolkit] +** [http://github.com/agentzh/redis2-nginx-module ngx_redis2] + +The order in which these modules are added during configuration is important because the position of any filter module in the +filtering chain determines the final output, for example. The correct adding order is shown above. + +* 3rd-party Lua libraries: +** [http://www.kyne.com.au/~mark/software/lua-cjson.php lua-cjson] * Applications: ** mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' -** memcached - -The order in which these modules are added during configuration is important as the position of any filter module in the -filtering chain determines the final output. The correct adding order is: - -# ngx_devel_kit -# set-misc-nginx-module -# ngx_http_auth_request_module -# echo-nginx-module -# memc-nginx-module -# lua-nginx-module (i.e. this module) -# headers-more-nginx-module -# srcache-nginx-module -# drizzle-nginx-module -# rds-json-nginx-module +** memcached: listening on the default port, 11211. +** redis: listening on the default port, 6379. + +See also the [https://github.com/chaoslawful/lua-nginx-module/blob/master/util/build2.sh developer build script] for more details on setting up the testing environment. + +To run the whole test suite in the default testing mode: + + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib -r t + + +To run specific test files: + + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t + + +To run a specific test block in a particular test file, add the line --- ONLY to the test block you want to run, and then use the `prove` utility to run that .t file. + +There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [http://search.cpan.org/perldoc?Test::Nginx Test::Nginx documentation] for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: http://qa.openresty.org. = Copyright and License = From c4657a35b25f1a984534d500f1edc32f2cf18e30 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 25 Sep 2013 16:28:55 -0700 Subject: [PATCH 0252/1981] feature: now we allow use the raw request cosocket returned by ngx.req.socket(true) to send the raw HTTP response header. thanks aviramc for requesting this in #242. also we now always enable "lingering close" in the nginx core when raw req sockets are used. --- src/ngx_http_lua_socket_tcp.c | 7 ++++--- t/116-raw-req-socket.t | 20 ++++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 4d25ef83c5..d27edbb60a 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3168,9 +3168,9 @@ ngx_http_lua_req_socket(lua_State *L) } if (!r->header_sent) { - lua_pushnil(L); - lua_pushliteral(L, "response header not sent yet"); - return 2; + /* prevent other parts of nginx from sending out + * the response header */ + r->header_sent = 1; } dd("ctx acquired raw req socket: %d", ctx->acquired_raw_req_socket); @@ -3212,6 +3212,7 @@ ngx_http_lua_req_socket(lua_State *L) ctx->acquired_raw_req_socket = 1; r->keepalive = 0; + r->lingering_close = 1; #endif } else { diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index 92f8a74802..e0d2de22a7 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 26; +plan tests => repeat_each() * 29; our $HtmlDir = html_dir; @@ -119,18 +119,26 @@ lua raw req socket tcp_nodelay ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) return end + local ok, err = sock:send("HTTP/1.1 200 OK\\r\\nContent-Length: 5\\r\\n\\r\\nhello") + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return + end '; } --- raw_request eval "GET /t HTTP/1.0\r Host: localhost\r -Upgrade: mysocket\r +Content-Length: 5\r \r hello" ---- ignore_response ---- error_log -server: failed to get raw req socket: response header not sent yet +--- response_headers +Content-Length: 5 +--- response_body chop +hello +--- no_error_log +[error] @@ -144,7 +152,7 @@ server: failed to get raw req socket: response header not sent yet local sock, err = ngx.req.socket(true) if not sock then ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) - return + return ngx.exit(500) end '; } From 8e6c9a312d53c45d09c46646b95b799b21bbf582 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 27 Sep 2013 12:49:33 -0700 Subject: [PATCH 0253/1981] change: raised the "lua_code_cache is off" warning to an alert. --- src/ngx_http_lua_directive.c | 2 +- t/025-codecache.t | 47 +++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index ba4c9c8833..830503daf5 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -124,7 +124,7 @@ ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) fp = (ngx_flag_t *) (p + cmd->offset); if (!*fp) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, "lua_code_cache is off; this will hurt " "performance"); } diff --git a/t/025-codecache.t b/t/025-codecache.t index 0ee1ea8998..2472c94282 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 3 + 1); #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; @@ -45,6 +45,8 @@ GET /main 32 updated 32 +--- no_error_log +[alert] @@ -77,6 +79,8 @@ GET /main 32 updated 32 +--- no_error_log +[alert] @@ -109,6 +113,9 @@ GET /main 32 updated 101 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -142,6 +149,9 @@ GET /main 32 updated 101 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -176,6 +186,8 @@ GET /main 32 updated 32 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ @@ -212,6 +224,8 @@ GET /main 32 updated 102 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ @@ -248,6 +262,8 @@ GET /main 32 updated 102 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ @@ -285,6 +301,8 @@ GET /main 32 updated 102 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ @@ -322,6 +340,8 @@ GET /main 32 updated 32 +--- no_error_log +[alert] @@ -355,6 +375,8 @@ GET /main 32 updated 101 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ @@ -388,6 +410,8 @@ GET /main 32 updated 32 +--- no_error_log +[alert] @@ -412,6 +436,9 @@ ngx.say(table.concat({1,2,3}, ", ")) 1, 2, 3 5 1, 2, 3 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -435,6 +462,9 @@ ngx.say(table.concat({1,2,3}, ", ")) 1, 2, 3 5 1, 2, 3 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -469,6 +499,9 @@ ngx.say("OK") --- response_body OK OK +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -517,6 +550,9 @@ loading hello, foo found found +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -565,6 +601,9 @@ loading hello, foo found found +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -587,6 +626,9 @@ found GET /t --- response_body _G.foo: 1 +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + @@ -614,4 +656,7 @@ GET /t ^table: 0x\d*?[1-9a-fA-F] --- no_error_log [error] +--- error_log eval +qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ + From 04e53ee374bac6f7dba1dadf332794ecddd8e145 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 27 Sep 2013 12:55:01 -0700 Subject: [PATCH 0254/1981] bugfix: Lua VM might run out of memory when lua_code_cache is off; now we always enforce a full Lua GC cycle right after unloading most of the loaded Lua modules when the Lua code cache is turned off. --- src/ngx_http_lua_cache.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 85332edd0d..68efeff579 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -406,6 +406,9 @@ ngx_http_lua_clear_package_loaded(lua_State *L) /* package loaded */ lua_pop(L, 2); + /* force a full GC cycle */ + lua_gc(L, LUA_GCCOLLECT, 0); + #if 0 lua_newtable(L); lua_setglobal(L, "_G"); From eabadd9b2295a5238a4fafb8492c091895b33655 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 27 Sep 2013 13:28:43 -0700 Subject: [PATCH 0255/1981] docs: documented the new ngx.req.socket(true) API, upon which fancy protocols like WebSocket can be implemented. --- README | 28 +++++++++++++++++++++++++--- README.markdown | 9 ++++++++- doc/HttpLuaModule.wiki | 9 ++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/README b/README index 08109ac422..6d7bb75629 100644 --- a/README +++ b/README @@ -2946,6 +2946,8 @@ Nginx API for Lua ngx.req.socket syntax: *tcpsock, err = ngx.req.socket()* + syntax: *tcpsock, err = ngx.req.socket(raw)* + context: *rewrite_by_lua*, access_by_lua*, content_by_lua** Returns a read-only cosocket object that wraps the downstream @@ -2962,9 +2964,29 @@ Nginx API for Lua If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to - avoid potential data loss resulting from such pre-reading. - - Chunked request bodies are not yet supported in this API. + avoid potential data loss resulting from such pre-reading. Chunked + request bodies are not yet supported in this API. + + Since the "v0.9.0" release, this function accepts an optional boolean + "raw" argument. When this argument is "true", this function returns a + full duplex cosocket object wrapping around the raw downstream + connection socket, upon which you can call the receive, receiveuntil, + and send methods. + + When the "raw" argument is "true", it is required that no pending data + from any previous ngx.say, ngx.print, or ngx.send_headers calls exists. + So if you have these downstream output calls previously, you should call + ngx.flush(true) before calling "ngx.req.socket(true)" to ensure that + there is no pending output data. Another requirement for this case is + that the request body must have already been read completely. + + You can use the "raw request socket" returned by "ngx.req.socket(true)" + to implement fancy protocols like WebSocket + (), or just emit your own raw + HTTP response header or body data. You can refer to the + lua-resty-websocket library + () for a real world + example. This function was first introduced in the "v0.5.0rc1" release. diff --git a/README.markdown b/README.markdown index b07b7baca3..ce46d3d045 100644 --- a/README.markdown +++ b/README.markdown @@ -2710,6 +2710,8 @@ ngx.req.socket -------------- **syntax:** *tcpsock, err = ngx.req.socket()* +**syntax:** *tcpsock, err = ngx.req.socket(raw)* + **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** Returns a read-only cosocket object that wraps the downstream connection. Only [receive](http://wiki.nginx.org/HttpLuaModule#tcpsock:receive) and [receiveuntil](http://wiki.nginx.org/HttpLuaModule#tcpsock:receiveuntil) methods are supported on this object. @@ -2719,9 +2721,14 @@ In case of error, `nil` will be returned as well as a string describing the erro The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) directive, and do not mix this call with [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) and [ngx.req.discard_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.discard_body). If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. - Chunked request bodies are not yet supported in this API. +Since the `v0.9.0` release, this function accepts an optional boolean `raw` argument. When this argument is `true`, this function returns a full duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [receive](http://wiki.nginx.org/HttpLuaModule#tcpsock:receive), [receiveuntil](http://wiki.nginx.org/HttpLuaModule#tcpsock:receiveuntil), and [send](http://wiki.nginx.org/HttpLuaModule#tcpsock:send) methods. + +When the `raw` argument is `true`, it is required that no pending data from any previous [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say), [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print), or [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers) calls exists. So if you have these downstream output calls previously, you should call [ngx.flush(true)](http://wiki.nginx.org/HttpLuaModule#ngx.flush) before calling `ngx.req.socket(true)` to ensure that there is no pending output data. Another requirement for this case is that the request body must have already been read completely. + +You can use the "raw request socket" returned by `ngx.req.socket(true)` to implement fancy protocols like [WebSocket](http://en.wikipedia.org/wiki/WebSocket), or just emit your own raw HTTP response header or body data. You can refer to the [lua-resty-websocket library](https://github.com/agentzh/lua-resty-websocket) for a real world example. + This function was first introduced in the `v0.5.0rc1` release. ngx.exec diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 4167789e00..b32f634053 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2626,6 +2626,8 @@ See also [[#ngx.req.init_body|ngx.req.init_body]]. == ngx.req.socket == '''syntax:''' ''tcpsock, err = ngx.req.socket()'' +'''syntax:''' ''tcpsock, err = ngx.req.socket(raw)'' + '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' Returns a read-only cosocket object that wraps the downstream connection. Only [[#tcpsock:receive|receive]] and [[#tcpsock:receiveuntil|receiveuntil]] methods are supported on this object. @@ -2635,9 +2637,14 @@ In case of error, nil will be returned as well as a string describi The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [[#lua_need_request_body|lua_need_request_body]] directive, and do not mix this call with [[#ngx.req.read_body|ngx.req.read_body]] and [[#ngx.req.discard_body|ngx.req.discard_body]]. If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading. - Chunked request bodies are not yet supported in this API. +Since the v0.9.0 release, this function accepts an optional boolean raw argument. When this argument is true, this function returns a full duplex cosocket object wrapping around the raw downstream connection socket, upon which you can call the [[#tcpsock:receive|receive]], [[#tcpsock:receiveuntil|receiveuntil]], and [[#tcpsock:send|send]] methods. + +When the raw argument is true, it is required that no pending data from any previous [[#ngx.say|ngx.say]], [[#ngx.print|ngx.print]], or [[#ngx.send_headers|ngx.send_headers]] calls exists. So if you have these downstream output calls previously, you should call [[#ngx.flush|ngx.flush(true)]] before calling ngx.req.socket(true) to ensure that there is no pending output data. Another requirement for this case is that the request body must have already been read completely. + +You can use the "raw request socket" returned by ngx.req.socket(true) to implement fancy protocols like [http://en.wikipedia.org/wiki/WebSocket WebSocket], or just emit your own raw HTTP response header or body data. You can refer to the [https://github.com/agentzh/lua-resty-websocket lua-resty-websocket library] for a real world example. + This function was first introduced in the v0.5.0rc1 release. == ngx.exec == From 2063a94b2bf2d00f8fa916e2380e89ec7a574421 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 29 Sep 2013 20:39:13 -0700 Subject: [PATCH 0256/1981] docs: bumped version to 0.9.0 and mentioned lua-resty-websocket and lua-resty-lock. --- README | 11 +++++++++-- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README b/README index 6d7bb75629..38c9dafd1d 100644 --- a/README +++ b/README @@ -8,8 +8,8 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.8.10 - () released on 22 + This document describes ngx_lua v0.9.0 + () released on 29 September 2013. Synopsis @@ -6289,9 +6289,16 @@ See Also * lua-resty-dns () library based on ngx_lua cosocket. + * lua-resty-websocket + () library for both + WebSocket server and client, based on ngx_lua cosocket. + * lua-resty-string () library based on LuaJIT FFI (). + * lua-resty-lock () library + for a nonblocking simple lock API. + * Routing requests to different MySQL queries based on URI arguments () diff --git a/README.markdown b/README.markdown index ce46d3d045..0814e8f472 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.8.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 September 2013. +This document describes ngx_lua [v0.9.0](https://github.com/chaoslawful/lua-nginx-module/tags) released on 29 September 2013. Synopsis ======== @@ -5509,7 +5509,9 @@ See Also * [lua-resty-mysql](http://github.com/agentzh/lua-resty-mysql) library based on ngx_lua cosocket. * [lua-resty-upload](http://github.com/agentzh/lua-resty-upload) library based on ngx_lua cosocket. * [lua-resty-dns](http://github.com/agentzh/lua-resty-dns) library based on ngx_lua cosocket. +* [lua-resty-websocket](http://github.com/agentzh/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. * [lua-resty-string](http://github.com/agentzh/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). +* [lua-resty-lock](http://github.com/agentzh/lua-resty-lock) library for a nonblocking simple lock API. * [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) * [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) * [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b32f634053..bf07de6a4d 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.8.10] released on 22 September 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.0] released on 29 September 2013. = Synopsis = @@ -5317,7 +5317,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * [http://github.com/agentzh/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. * [http://github.com/agentzh/lua-resty-upload lua-resty-upload] library based on ngx_lua cosocket. * [http://github.com/agentzh/lua-resty-dns lua-resty-dns] library based on ngx_lua cosocket. +* [http://github.com/agentzh/lua-resty-websocket lua-resty-websocket] library for both WebSocket server and client, based on ngx_lua cosocket. * [http://github.com/agentzh/lua-resty-string lua-resty-string] library based on [http://luajit.org/ext_ffi.html LuaJIT FFI]. +* [http://github.com/agentzh/lua-resty-lock lua-resty-lock] library for a nonblocking simple lock API. * [http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs Routing requests to different MySQL queries based on URI arguments] * [http://openresty.org/#DynamicRoutingBasedOnRedis Dynamic Routing Based on Redis and Lua] * [http://openresty.org/#UsingLuaRocks Using LuaRocks with ngx_lua] From f998256247c3df99483466902a618f8ac214692d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 1 Oct 2013 22:49:42 -0700 Subject: [PATCH 0257/1981] reindexed the 025-codecache.t test file. --- t/025-codecache.t | 8 -------- 1 file changed, 8 deletions(-) diff --git a/t/025-codecache.t b/t/025-codecache.t index 2472c94282..b500d88562 100644 --- a/t/025-codecache.t +++ b/t/025-codecache.t @@ -118,7 +118,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 4: code cache explicitly off (server level) --- config lua_code_cache off; @@ -154,7 +153,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 5: code cache explicitly off (server level) but be overridden in the location --- config lua_code_cache off; @@ -441,7 +439,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 13: no clear builtin lib "string" --- config location /lua { @@ -467,7 +464,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 14: no clear builtin lib "string" --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" @@ -504,7 +500,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 15: skip luarocks --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua'; @@ -555,7 +550,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 16: skip luarocks* --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua'; @@ -606,7 +600,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 17: clear _G table --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" @@ -631,7 +624,6 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/ - === TEST 18: github #257: globals cleared when code cache off --- http_config lua_code_cache off; From d8a266497a7078de0b5ecbc71da07917462af335 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 1 Oct 2013 23:05:04 -0700 Subject: [PATCH 0258/1981] optimize: now we pre-calculate the exact size of the resulting Lua table and preallocate the table space, which makes it 8%+ faster for a request with a dozen request headers and 40%+ faster for a hundred request headers. --- src/ngx_http_lua_headers.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 3afbd7ba76..bb9cde48a7 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -322,7 +322,18 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) ngx_http_lua_check_fake_request(L, r); - lua_createtable(L, 0, 4); + part = &r->headers_in.headers.part; + count = part->nelts; + while (part->next) { + part = part->next; + count += part->nelts; + } + + if (max > 0 && count > max) { + count = max; + } + + lua_createtable(L, 0, count); if (!raw) { lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key); @@ -366,7 +377,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) "lua request header: \"%V: %V\"", &header[i].key, &header[i].value); - if (max > 0 && ++count == max) { + if (--count == 0) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua hit request header limit %d", max); From 789e36b49b47ff032f0c3e31b6df4b3ab1148e0f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 15:35:00 -0700 Subject: [PATCH 0259/1981] feature: added the new configuration directive "lua_use_default_type" for controlling whether to send out a default Content-Type response header (as defined by the "default_type" directive). default on. thanks aviramc for the patch in #286. --- src/ngx_http_lua_common.h | 1 + src/ngx_http_lua_headers.c | 2 +- src/ngx_http_lua_module.c | 10 ++++++++++ src/ngx_http_lua_util.c | 2 +- src/ngx_http_lua_util.h | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index b03d7bb994..99df08f259 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -201,6 +201,7 @@ typedef struct { ngx_flag_t transform_underscores_in_resp_headers; ngx_flag_t log_socket_errors; ngx_flag_t check_client_abort; + ngx_flag_t use_default_type; } ngx_http_lua_loc_conf_t; diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index bb9cde48a7..bfaf38e530 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -497,7 +497,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) } if (!ctx->headers_set) { - rc = ngx_http_set_content_type(r); + rc = ngx_http_lua_set_content_type(r); if (rc != NGX_OK) { return luaL_error(L, "failed to set default content type: %d", diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 163f6d64e2..855a670c5a 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -343,6 +343,14 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, check_client_abort), NULL }, + { ngx_string("lua_use_default_type"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, use_default_type), + NULL }, + ngx_null_command }; @@ -616,6 +624,7 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) conf->enable_code_cache = NGX_CONF_UNSET; conf->http10_buffering = NGX_CONF_UNSET; conf->check_client_abort = NGX_CONF_UNSET; + conf->use_default_type = NGX_CONF_UNSET; conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; conf->connect_timeout = NGX_CONF_UNSET_MSEC; @@ -679,6 +688,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->enable_code_cache, prev->enable_code_cache, 1); ngx_conf_merge_value(conf->http10_buffering, prev->http10_buffering, 1); ngx_conf_merge_value(conf->check_client_abort, prev->check_client_abort, 0); + ngx_conf_merge_value(conf->use_default_type, prev->use_default_type, 1); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 60000); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 481f95a135..457877bdce 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -484,7 +484,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set && ngx_http_set_content_type(r) != NGX_OK) { + if (!ctx->headers_set && ngx_http_lua_set_content_type(r) != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 72855692cc..af09f6c6d8 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -249,6 +249,20 @@ ngx_http_lua_hash_str(u_char *src, size_t n) } +static ngx_inline ngx_int_t +ngx_http_lua_set_content_type(ngx_http_request_t *r) +{ + ngx_http_lua_loc_conf_t *llcf; + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (llcf->use_default_type) { + return ngx_http_set_content_type(r); + } + + return NGX_OK; +} + + extern ngx_uint_t ngx_http_lua_location_hash; extern ngx_uint_t ngx_http_lua_content_length_hash; From e5d47c4488742787ac38be64cd45c2ae91cd898e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 16:01:12 -0700 Subject: [PATCH 0260/1981] bugfix: we always printed the "lua hit request header limit" debug log message even when the limit is not hit at all. this regression had appeared in commit d8a266497a. --- src/ngx_http_lua_headers.c | 5 ++--- t/028-req-header.t | 9 ++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index bfaf38e530..c9d89aa941 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -331,6 +331,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) if (max > 0 && count > max) { count = max; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exceeding request header limit %d", max); } lua_createtable(L, 0, count); @@ -378,9 +380,6 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) &header[i].key, &header[i].value); if (--count == 0) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua hit request header limit %d", max); - return 1; } } diff --git a/t/028-req-header.t b/t/028-req-header.t index dff3dd8c3c..c1270a37f7 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -9,7 +9,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (2 * blocks() + 18); +plan tests => repeat_each() * (2 * blocks() + 19); #no_diff(); #no_long_string(); @@ -34,6 +34,9 @@ Bar: baz --- response_body Foo: bar Bar: baz +--- log_level: debug +--- no_error_log +lua exceeding request header limit @@ -427,7 +430,7 @@ for my $k (@k) { CORE::join("", @k); --- timeout: 4 --- error_log -lua hit request header limit 100 +lua exceeding request header limit 100 @@ -475,7 +478,7 @@ for my $k (@k) { CORE::join("", @k); --- timeout: 4 --- error_log -lua hit request header limit 102 +lua exceeding request header limit 102 From 3740962968a43b269fd2f3fd3d1bcad26cbe0fba Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 16:58:11 -0700 Subject: [PATCH 0261/1981] added tests for the new lua_use_default_type directive. --- t/118-use-default-type.t | 122 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 t/118-use-default-type.t diff --git a/t/118-use-default-type.t b/t/118-use-default-type.t new file mode 100644 index 0000000000..6a41d49c70 --- /dev/null +++ b/t/118-use-default-type.t @@ -0,0 +1,122 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use t::TestNginxLua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +#log_level 'warn'; +log_level 'debug'; + +#no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: lua_use_default_type default on +--- config + location /lua { + default_type text/plain; + content_by_lua ' + ngx.say("hello") + '; + } +--- request +GET /lua +--- response_body +hello +--- response_headers +Content-Type: text/plain +--- no_error_log +[error] + + + +=== TEST 2: lua_use_default_type explicitly on +--- config + lua_use_default_type on; + location /lua { + default_type text/plain; + content_by_lua ' + ngx.say("hello") + '; + } +--- request +GET /lua +--- response_body +hello +--- response_headers +Content-Type: text/plain +--- no_error_log +[error] + + + +=== TEST 3: lua_use_default_type off +--- config + lua_use_default_type off; + location /lua { + default_type text/plain; + content_by_lua ' + ngx.say("hello") + '; + } +--- request +GET /lua +--- response_body +hello +--- response_headers +!Content-Type +--- no_error_log +[error] + + + +=== TEST 4: overriding lua_use_default_type off +--- config + lua_use_default_type off; + location /lua { + lua_use_default_type on; + default_type text/plain; + content_by_lua ' + ngx.say("hello") + '; + } +--- request +GET /lua +--- response_body +hello +--- response_headers +Content-Type: text/plain +--- no_error_log +[error] + + + +=== TEST 5: overriding lua_use_default_type on +--- config + lua_use_default_type on; + location /lua { + lua_use_default_type off; + default_type text/plain; + content_by_lua ' + ngx.say("hello") + '; + } +--- request +GET /lua +--- response_body +hello +--- response_headers +!Content-Type +--- no_error_log +[error] + From ebf9cc8679c89d9330dbc0fe3d3e72ecd9c51b2b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 17:10:48 -0700 Subject: [PATCH 0262/1981] feature: now the raw request cosocket returned by ngx.req.socket() no longer requires the request body to be read already, which means that one can use this cosocket to read the raw request body data as well. thanks aviramc for the original patch. --- src/ngx_http_lua_socket_tcp.c | 8 ++++--- t/116-raw-req-socket.t | 42 ++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index d27edbb60a..c997b63ba4 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3150,9 +3150,11 @@ ngx_http_lua_req_socket(lua_State *L) return 2; #else if (!r->request_body) { - lua_pushnil(L); - lua_pushliteral(L, "requesty body not read yet"); - return 2; + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { + return luaL_error(L, "out of memory"); + } + r->request_body = rb; } if (c->buffered) { diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index e0d2de22a7..ff321888d8 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 29; +plan tests => repeat_each() * 33; our $HtmlDir = html_dir; @@ -695,3 +695,43 @@ msg: 1: received: hello, wo --- no_error_log [error] + + +=== TEST 13: request body not read yet +--- config + server_tokens off; + location = /t { + content_by_lua ' + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) + return + end + + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "failed to receive: ", err) + return + end + + local ok, err = sock:send("HTTP/1.1 200 OK\\r\\nContent-Length: 5\\r\\n\\r\\n" .. data) + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.0\r +Host: localhost\r +Content-Length: 5\r +\r +hello" +--- response_headers +Content-Length: 5 +--- response_body chop +hello +--- no_error_log +[error] + From fc03bfec344f4c42f97b2d3238760e7f7bd99568 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 17:35:56 -0700 Subject: [PATCH 0263/1981] bugfix: now ngx.req.socket(raw) returns proper error when there is some other "light thread" reading the request body. --- src/ngx_http_lua_socket_tcp.c | 10 +++++++- t/116-raw-req-socket.t | 46 ++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index c997b63ba4..f2b6f638ef 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3149,7 +3149,15 @@ ngx_http_lua_req_socket(lua_State *L) lua_pushliteral(L, "nginx version too old"); return 2; #else - if (!r->request_body) { + if (r->request_body) { + if (r->request_body->rest > 0) { + lua_pushnil(L); + lua_pushliteral(L, "pending request body reading in some " + "other thread"); + return 2; + } + + } else { rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return luaL_error(L, "out of memory"); diff --git a/t/116-raw-req-socket.t b/t/116-raw-req-socket.t index ff321888d8..94be797852 100644 --- a/t/116-raw-req-socket.t +++ b/t/116-raw-req-socket.t @@ -5,7 +5,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * 33; +plan tests => repeat_each() * 36; our $HtmlDir = html_dir; @@ -735,3 +735,47 @@ hello --- no_error_log [error] + + +=== TEST 14: pending request body reading +--- config + server_tokens off; + location = /t { + content_by_lua ' + ngx.thread.spawn(function () + ngx.req.read_body() + end) + + local sock, err = ngx.req.socket(true) + if not sock then + ngx.log(ngx.WARN, "server: failed to get raw req socket: ", err) + return ngx.exit(444) + end + + local data, err = sock:receive(5) + if not data then + ngx.log(ngx.ERR, "failed to receive: ", err) + return + end + + local ok, err = sock:send("HTTP/1.1 200 OK\\r\\nContent-Length: 5\\r\\n\\r\\n" .. data) + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return + end + '; + } + +--- raw_request eval +"GET /t HTTP/1.0\r +Host: localhost\r +Content-Length: 5\r +\r +hell" +--- ignore_response +--- no_error_log +[error] +[alert] +--- error_log +server: failed to get raw req socket: pending request body reading in some other thread + From cd669b556074aba37174f4b035e2050da824ec82 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Oct 2013 21:56:57 -0700 Subject: [PATCH 0264/1981] made a test case in 024-access/client-abort.t less possible to fail due to timing errors. --- t/024-access/client-abort.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 256bb10aa9..212c49dbd6 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -734,6 +734,7 @@ delete thread 2 lua req cleanup --- shutdown: 1 +--- wait: 0.1 --- ignore_response --- no_error_log [error] From bc43c4367aced6c5c34a4bc91041b20f39a3d0ea Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 6 Oct 2013 16:19:46 -0700 Subject: [PATCH 0265/1981] =?UTF-8?q?docs:=20added=20more=20explanation=20?= =?UTF-8?q?on=20subrequests'=20request=20body=20handling.=20thanks=20J?= =?UTF-8?q?=C4=99drzej=20Nowak=20for=20the=20suggestion.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README | 17 +++++++++++++---- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README b/README index 38c9dafd1d..e77d9548a8 100644 --- a/README +++ b/README @@ -1767,6 +1767,10 @@ Nginx API for Lua Subrequests are completely different from HTTP 301/302 redirection (via ngx.redirect) and internal redirection (via ngx.exec). + You should always read the request body (by either calling + ngx.req.read_body or configuring lua_need_request_body on) before + initiating a subrequest. + Here is a basic example: res = ngx.location.capture(uri) @@ -1835,10 +1839,15 @@ Nginx API for Lua * "always_forward_body" when set to true, the current (parent) request's request body will always be forwarded to the subrequest - being created if the "body" option is not specified. By default, - this option is false and when the "body" option is not specified, - the request body of the current (parent) request is only forwarded - when the subrequest takes the "PUT" or "POST" request method. + being created if the "body" option is not specified. The request + body read by either ngx.req.read_body() or lua_need_request_body on + will be directly forwarded to the subrequest without copying the + whole request body data when creating the subrequest (no matter the + request body data is buffered in memory buffers or temporary files). + By default, this option is "false" and when the "body" option is not + specified, the request body of the current (parent) request is only + forwarded when the subrequest takes the "PUT" or "POST" request + method. Issuing a POST subrequest, for example, can be done as follows diff --git a/README.markdown b/README.markdown index 0814e8f472..41d1cf308b 100644 --- a/README.markdown +++ b/README.markdown @@ -1574,6 +1574,8 @@ Also note that subrequests just mimic the HTTP interface but there is *no* extra Subrequests are completely different from HTTP 301/302 redirection (via [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect)) and internal redirection (via [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec)). +You should always read the request body (by either calling [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) or configuring [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) on) before initiating a subrequest. + Here is a basic example: @@ -1629,7 +1631,7 @@ argument, which supports the options: * `share_all_vars` specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. * `always_forward_body` - when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the `body` option is not specified. By default, this option is false and when the `body` option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the `PUT` or `POST` request method. + when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the `body` option is not specified. The request body read by either [ngx.req.read_body()](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) or [lua_need_request_body on](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is `false` and when the `body` option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the `PUT` or `POST` request method. Issuing a POST subrequest, for example, can be done as follows diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index bf07de6a4d..f9319d44ae 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1515,6 +1515,8 @@ Also note that subrequests just mimic the HTTP interface but there is ''no'' ext Subrequests are completely different from HTTP 301/302 redirection (via [[#ngx.redirect|ngx.redirect]]) and internal redirection (via [[#ngx.exec|ngx.exec]]). +You should always read the request body (by either calling [[#ngx.req.read_body|ngx.req.read_body]] or configuring [[#lua_need_request_body|lua_need_request_body]] on) before initiating a subrequest. + Here is a basic example: @@ -1570,7 +1572,7 @@ argument, which supports the options: * share_all_vars : specify whether to share all the Nginx variables of the subrequest with the current (parent) request. modifications of the Nginx variables in the subrequest will affect the current (parent) request. * always_forward_body -: when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the body option is not specified. By default, this option is false and when the body option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the PUT or POST request method. +: when set to true, the current (parent) request's request body will always be forwarded to the subrequest being created if the body option is not specified. The request body read by either [[#ngx.req.read_body|ngx.req.read_body()]] or [[#lua_need_request_body|lua_need_request_body on]] will be directly forwarded to the subrequest without copying the whole request body data when creating the subrequest (no matter the request body data is buffered in memory buffers or temporary files). By default, this option is false and when the body option is not specified, the request body of the current (parent) request is only forwarded when the subrequest takes the PUT or POST request method. Issuing a POST subrequest, for example, can be done as follows From 487618a801b32701e7b54d4a107c3153223c5413 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 11 Oct 2013 23:27:51 -0700 Subject: [PATCH 0266/1981] bugfix: header_filter_by_lua*, body_filter_by_lua*, and ngx.location.capture* might not work properly with multiple http {} blocks in nginx.conf. thanks flygoast for the report in #294. --- src/ngx_http_lua_module.c | 18 ++++++++-- t/079-unused-directives.t | 74 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 855a670c5a..84b48a57fd 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -45,6 +45,9 @@ static ngx_conf_post_t ngx_http_lua_lowat_post = { ngx_http_lua_lowat_check }; +static volatile ngx_cycle_t *ngx_http_lua_prev_cycle = NULL; + + static ngx_command_t ngx_http_lua_cmds[] = { { ngx_string("lua_max_running_timers"), @@ -389,6 +392,7 @@ ngx_module_t ngx_http_lua_module = { static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf) { + int multi_http_blocks; ngx_int_t rc; ngx_array_t *arr; ngx_http_handler_pt *h; @@ -397,7 +401,15 @@ ngx_http_lua_init(ngx_conf_t *cf) lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); - if (lmcf->requires_capture_filter) { + if (ngx_http_lua_prev_cycle != ngx_cycle) { + ngx_http_lua_prev_cycle = ngx_cycle; + multi_http_blocks = 0; + + } else { + multi_http_blocks = 1; + } + + if (multi_http_blocks || lmcf->requires_capture_filter) { rc = ngx_http_lua_capture_filter_init(cf); if (rc != NGX_OK) { return rc; @@ -446,14 +458,14 @@ ngx_http_lua_init(ngx_conf_t *cf) *h = ngx_http_lua_log_handler; } - if (lmcf->requires_header_filter) { + if (multi_http_blocks || lmcf->requires_header_filter) { rc = ngx_http_lua_header_filter_init(); if (rc != NGX_OK) { return rc; } } - if (lmcf->requires_body_filter) { + if (multi_http_blocks || lmcf->requires_body_filter) { rc = ngx_http_lua_body_filter_init(); if (rc != NGX_OK) { return rc; diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t index dab7bb8f4d..91aa2fc37a 100644 --- a/t/079-unused-directives.t +++ b/t/079-unused-directives.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (11 * blocks()); +plan tests => repeat_each() * 120; #no_diff(); #no_long_string(); @@ -261,3 +261,75 @@ lua capture body filter, uri "/t" lua log handler, uri:"/t" [error] + + +=== TEST 11: header_filter_by_lua with multiple http blocks (github issue #294) +--- config + location = /t { + echo ok; + header_filter_by_lua ' + ngx.status = 201 + ngx.header.Foo = "foo" + '; + + } +--- post_main_config + http { + } +--- request +GET /t +--- response_headers +Foo: foo +--- response_body +ok +--- error_code: 201 +--- no_error_log +[error] + + + +=== TEST 12: body_filter_by_lua in multiple http blocks (github issue #294) +--- config + location = /t { + echo -n ok; + body_filter_by_lua ' + if ngx.arg[2] then + ngx.arg[1] = ngx.arg[1] .. "ay\\n" + end + '; + + } +--- post_main_config + http { + } +--- request +GET /t +--- response_body +okay +--- no_error_log +[error] + + + +=== TEST 13: capture filter with multiple http blocks (github issue #294) +--- config + location = /t { + content_by_lua ' + local res = ngx.location.capture("/sub") + ngx.say("sub: ", res.body) + '; + } + + location = /sub { + echo -n sub; + } +--- post_main_config + http { + } +--- request +GET /t +--- response_body +sub: sub +--- no_error_log +[error] + From 01bf02aa044fbdccad1218784534989b78dd3f28 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 10:38:54 -0700 Subject: [PATCH 0267/1981] bugfix: the original lettercase of the header name was lost when creating the Cache-Control response header via the ngx.header.HEADER API. --- src/ngx_http_lua_headers_out.c | 2 +- t/016-resp-header.t | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 2ee10d1ffb..1437845c75 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -338,7 +338,7 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, ho->value = *value; ho->hash = hv->hash; - ngx_str_set(&ho->key, "Cache-Control"); + ho->key = hv->key; *ph = ho; return NGX_OK; diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 135aa082d4..ad03227293 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -1047,3 +1047,20 @@ Foo: /t/ --- no_error_log [error] + + +=== TEST 52: case sensitive cache-control header +--- config + location /lua { + content_by_lua ' + ngx.header["cache-Control"] = "private" + ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) + '; + } +--- request + GET /lua +--- raw_response_headers_like chop +cache-Control: private +--- response_body +Cache-Control: private + From c304f3592180c141e473d8883a94e29337b51b42 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 11:02:51 -0700 Subject: [PATCH 0268/1981] bugfix: when there were no existing Cache-Control response headers, "ngx.header.cache_control = nil" would (incorrectly) create a new Cache-Control header with an empty value. thanks jinglong for the patch. --- src/ngx_http_lua_headers_out.c | 9 ++++++++- t/016-resp-header.t | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 1437845c75..c3e93ba4d7 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -337,7 +337,14 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, } ho->value = *value; - ho->hash = hv->hash; + + if (value->len == 0) { + ho->hash = 0; + + } else { + ho->hash = hv->hash; + } + ho->key = hv->key; *ph = ho; diff --git a/t/016-resp-header.t b/t/016-resp-header.t index ad03227293..6d73e56b89 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -1064,3 +1064,20 @@ cache-Control: private --- response_body Cache-Control: private + + +=== TEST 53: clear Cache-Control when there was no Cache-Control +--- config + location /lua { + content_by_lua ' + ngx.header["Cache-Control"] = nil + ngx.say("Cache-Control: ", ngx.var.sent_http_cache_control) + '; + } +--- request + GET /lua +--- raw_response_headers_unlike eval +qr/Cache-Control/i +--- response_body +Cache-Control: nil + From bc84964477326ecf00ef594731c2573152bfee2d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:11:54 -0700 Subject: [PATCH 0269/1981] optimize: preallocate space for the "coroutine" lua table. --- src/ngx_http_lua_coroutine.c | 2 +- t/062-count.t | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 85c30b542d..1e6fbc6b22 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -225,7 +225,7 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) int rc; /* new coroutine table */ - lua_newtable(L); + lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* get old coroutine table */ lua_getglobal(L, "coroutine"); diff --git a/t/062-count.t b/t/062-count.t index f425b8e4a8..0ac85067c2 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -363,3 +363,31 @@ n = 4 --- no_error_log [error] + + +=== TEST 17: entries under coroutine. (content by lua) +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(coroutine) do + n = n + 1 + end + ngx.say("coroutine: ", n) + '; + } +--- request +GET /test +--- stap +global c +probe process("$LIBLUA_PATH").function("rehashtab") { + c++ + printf("rehash: %d\n", c) +} +--- stap_out +3 +--- response_body +coroutine: 10 +--- no_error_log +[error] + From 136087f328dcf9c3e2821ae1e544e59e20941578 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:11:54 -0700 Subject: [PATCH 0270/1981] optimize: preallocate space for the "coroutine" lua table. --- src/ngx_http_lua_coroutine.c | 2 +- t/062-count.t | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 85c30b542d..1e6fbc6b22 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -225,7 +225,7 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) int rc; /* new coroutine table */ - lua_newtable(L); + lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* get old coroutine table */ lua_getglobal(L, "coroutine"); diff --git a/t/062-count.t b/t/062-count.t index f425b8e4a8..fbf645b70e 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -363,3 +363,31 @@ n = 4 --- no_error_log [error] + + +=== TEST 17: entries under coroutine. (content by lua) +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(coroutine) do + n = n + 1 + end + ngx.say("coroutine: ", n) + '; + } +--- request +GET /test +--- stap2 +global c +probe process("$LIBLUA_PATH").function("rehashtab") { + c++ + printf("rehash: %d\n", c) +} +--- stap_out2 +3 +--- response_body +coroutine: 10 +--- no_error_log +[error] + From ace93e66fa189514b58539b5b824cc59bcc1f44a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:19:08 -0700 Subject: [PATCH 0271/1981] optimize: preallocate space for the "ngx.thread" lua table during API initialization. --- src/ngx_http_lua_uthread.c | 2 +- t/062-count.t | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index a93b84c553..172cfe8c4d 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -30,7 +30,7 @@ void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) { /* new thread table */ - lua_newtable(L); + lua_createtable(L, 0 /* narr */, 2 /* nrec */); lua_pushcfunction(L, ngx_http_lua_uthread_spawn); lua_setfield(L, -2, "spawn"); diff --git a/t/062-count.t b/t/062-count.t index fbf645b70e..f3da149949 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -391,3 +391,30 @@ coroutine: 10 --- no_error_log [error] + + +=== TEST 18: entries under ngx.thread. (content by lua) +--- config + location = /test { + content_by_lua ' + local n = 0 + for k, v in pairs(ngx.thread) do + n = n + 1 + end + ngx.say("thread: ", n) + '; + } +--- request +GET /test +--- stap2 +global c +probe process("$LIBLUA_PATH").function("rehashtab") { + c++ + printf("rehash: %d\n", c) +} +--- stap_out2 +--- response_body +thread: 2 +--- no_error_log +[error] + From 101f8d9ed477ae6fda9d9902b6df4d51ddeade2c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:36:38 -0700 Subject: [PATCH 0272/1981] optimize: preallocate 4 hashtable slots in the ngx.ctx tables. --- src/ngx_http_lua_ctx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_ctx.c b/src/ngx_http_lua_ctx.c index 1bca45b251..f99fa2d170 100644 --- a/src/ngx_http_lua_ctx.c +++ b/src/ngx_http_lua_ctx.c @@ -36,7 +36,7 @@ ngx_http_lua_ngx_get_ctx(lua_State *L) lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); - lua_newtable(L); + lua_createtable(L, 0 /* narr */, 4 /* nrec */); lua_pushvalue(L, -1); ctx->ctx_ref = luaL_ref(L, -3); return 1; From 0b3c47a3bf8bf3812712c4e73f7594b65997695f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:43:08 -0700 Subject: [PATCH 0273/1981] optimize: preallocate the space for the metatable for the global environment table for header_filter_by_lua*, body_filter_by_lua*, and log_by_lua*. --- src/ngx_http_lua_bodyfilterby.c | 3 ++- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_logby.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index fa55e68c41..c13f777fe6 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -73,7 +73,8 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ - lua_newtable(L); /* the metatable for the new env */ + lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new + env */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 0f62166e03..d5f2705a8b 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -71,7 +71,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* }}} */ /* {{{ make new env inheriting main thread's globals table */ - lua_newtable(L); /* the metatable for the new env */ + lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 4fde5d3aa9..f91728b295 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -54,7 +54,7 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ - lua_newtable(L); /* the metatable for the new env */ + lua_createtable(L, 0, 1); /* the metatable for the new env */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ From 054444dd4183291c22ce7b783e02521205aacf4f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 18:57:42 -0700 Subject: [PATCH 0274/1981] optimize: preallocate some space in our Lua registry tables to reduce the initial requests' "warm-up" time a bit. --- src/ngx_http_lua_util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 457877bdce..91fba5219a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -703,31 +703,31 @@ ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L) /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); - lua_newtable(L); + lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ /* create the registry entry for the Lua request ctx data table */ lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); - lua_newtable(L); + lua_createtable(L, 0, 32 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* create the registry entry for the Lua socket connection pool table */ lua_pushlightuserdata(L, &ngx_http_lua_socket_pool_key); - lua_newtable(L); + lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #if (NGX_PCRE) /* create the registry entry for the Lua precompiled regex object cache */ lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); - lua_newtable(L); + lua_createtable(L, 0, 16 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); #endif /* {{{ register table to cache user code: * { [(string)cache_key] = } */ lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); - lua_newtable(L); + lua_createtable(L, 0, 8 /* nrec */); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ } From ca90ef434e616056a7f4572d680ec63ca229c768 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 19:18:08 -0700 Subject: [PATCH 0275/1981] optimize: pre-allocate space for the resulting Lua tables in ngx.location.capture*. --- src/ngx_http_lua_subrequest.c | 15 +++++++++++---- t/020-subrequest.t | 8 ++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index bb10fff4b0..4ff75b45c0 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1214,7 +1214,7 @@ static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { - ngx_uint_t i; + ngx_uint_t i, count; ngx_uint_t index; lua_State *co; ngx_str_t *body_str; @@ -1239,7 +1239,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, (int) r->uri.len, r->uri.data); /* {{{ construct ret value */ - lua_newtable(co); + lua_createtable(co, 0 /* narr */, 4 /* nrec */); /* copy captured status */ lua_pushinteger(co, coctx->sr_statuses[index]); @@ -1271,10 +1271,17 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, /* copy captured headers */ - lua_newtable(co); /* res.header */ - sr_headers = coctx->sr_headers[index]; + part = &sr_headers->headers.part; + count = part->nelts; + while (part->next) { + part = part->next; + count += part->nelts; + } + + lua_createtable(co, 0, count + 5); /* res.header */ + dd("saving subrequest response headers"); part = &sr_headers->headers.part; diff --git a/t/020-subrequest.t b/t/020-subrequest.t index cd7ff98fd5..db507ca92c 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -2385,6 +2385,14 @@ hello world --- 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 From b41f546c7ba9b1a5d1765821d534db384d45ff3c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Oct 2013 19:45:32 -0700 Subject: [PATCH 0276/1981] fixed the preallocation size for the "coroutine" Lua table. --- src/ngx_http_lua_coroutine.c | 2 +- t/062-count.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 7d4da03ea7..6ec0ca5a06 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -225,7 +225,7 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) int rc; /* new coroutine table */ - lua_createtable(L, 0 /* narr */, 10 /* nrec */); + lua_createtable(L, 0 /* narr */, 11 /* nrec */); /* get old coroutine table */ lua_getglobal(L, "coroutine"); diff --git a/t/062-count.t b/t/062-count.t index f3da149949..411b33e561 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -387,7 +387,7 @@ probe process("$LIBLUA_PATH").function("rehashtab") { --- stap_out2 3 --- response_body -coroutine: 10 +coroutine: 11 --- no_error_log [error] From 335ad8cc9297113f05a5c2f7e6b4e7384880e26e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 13 Oct 2013 20:14:32 -0700 Subject: [PATCH 0277/1981] added a code comment regarding the "active_connections" field in ngx_http_lua_socket_pool_t. --- src/ngx_http_lua_socket_tcp.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index f977ef7133..68d0191b99 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -36,6 +36,9 @@ typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt)( typedef struct { ngx_http_lua_main_conf_t *conf; + + /* active connections == out-of-pool reused connections + * + in-pool connections */ ngx_uint_t active_connections; /* queues of ngx_http_lua_socket_pool_item_t: */ From 39ac6421afb6bcdfaf3eabc94fb79650b0d75724 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 14 Oct 2013 16:19:36 -0700 Subject: [PATCH 0278/1981] bugfix: ngx.req.set_header("Host", value) would overwrite the value of $host with bad values. thanks aviramc for the patch in #293 (and issue #292). --- src/ngx_http_lua_headers_in.c | 108 +++++++++++++++++++++++++++++++++- t/028-req-header.t | 34 +++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index b3ae70b08a..ac0baaa7c3 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -35,6 +35,8 @@ static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool, + ngx_uint_t alloc); static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l, @@ -273,13 +275,117 @@ ngx_http_set_builtin_header(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) +{ + u_char *h, ch; + size_t i, dot_pos, host_len; + + enum { + sw_usual = 0, + sw_literal, + sw_rest + } state; + + dot_pos = host->len; + host_len = host->len; + + h = host->data; + + state = sw_usual; + + for (i = 0; i < host->len; i++) { + ch = h[i]; + + switch (ch) { + + case '.': + if (dot_pos == i - 1) { + return NGX_DECLINED; + } + dot_pos = i; + break; + + case ':': + if (state == sw_usual) { + host_len = i; + state = sw_rest; + } + break; + + case '[': + if (i == 0) { + state = sw_literal; + } + break; + + case ']': + if (state == sw_literal) { + host_len = i + 1; + state = sw_rest; + } + break; + + case '\0': + return NGX_DECLINED; + + default: + + if (ngx_path_separator(ch)) { + return NGX_DECLINED; + } + + if (ch >= 'A' && ch <= 'Z') { + alloc = 1; + } + + break; + } + } + + if (dot_pos == host_len - 1) { + host_len--; + } + + if (host_len == 0) { + return NGX_DECLINED; + } + + if (alloc) { + host->data = ngx_pnalloc(pool, host_len); + if (host->data == NULL) { + return NGX_ERROR; + } + + ngx_strlow(host->data, h, host_len); + } + + host->len = host_len; + + return NGX_OK; +} + + static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value) { + ngx_str_t host; + dd("server new value len: %d", (int) value->len); - r->headers_in.server = *value; + if (value->len) { + host= *value; + + if (ngx_http_lua_validate_host(&host, r->pool, 0) != NGX_OK) { + return NGX_ERROR; + } + + r->headers_in.server = host; + + } else { + r->headers_in.server = *value; + } return ngx_http_set_builtin_header(r, hv, value); } diff --git a/t/028-req-header.t b/t/028-req-header.t index c1270a37f7..13c2c3dbcc 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -1312,3 +1312,37 @@ X-Foo: nil --- no_error_log [error] + + +=== TEST 42: Host header with port and $host (github issue #292) +--- config + location /bar { + rewrite_by_lua ' + ngx.req.set_header("Host", "agentzh.org:1984") + '; + echo "host var: $host"; + echo "http_host var: $http_host"; + } +--- request +GET /bar +--- response_body +host var: agentzh.org +http_host var: agentzh.org:1984 + + + +=== TEST 43: Host header with upper case letters and $host (github issue #292) +--- config + location /bar { + rewrite_by_lua ' + ngx.req.set_header("Host", "agentZH.org:1984") + '; + echo "host var: $host"; + echo "http_host var: $http_host"; + } +--- request +GET /bar +--- response_body +host var: agentzh.org +http_host var: agentZH.org:1984 + From f17fc0941962b5f4d12bd23d6cfa74819f08bece Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 15 Oct 2013 11:48:04 -0700 Subject: [PATCH 0279/1981] bugfix: the Lua error when ngx.sleep() was used in log_by_lua* was not friendly. thanks Jiale Zhi for the report. --- src/ngx_http_lua_sleep.c | 5 +++++ t/077-sleep.t | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 0660da7bb2..f0ca21887d 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -52,6 +52,11 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "no request ctx found"); } + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER); + coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); diff --git a/t/077-sleep.t b/t/077-sleep.t index 0884dcf8c8..619f0a1e51 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 40; +plan tests => repeat_each() * 43; #no_diff(); #no_long_string(); @@ -236,3 +236,21 @@ lua sleep timer expired: "/test?" --- no_error_log [error] + + +=== TEST 10: ngx.sleep unavailable in log_by_lua +--- config + location /t { + echo hello; + log_by_lua ' + ngx.sleep(0.1) + '; + } +--- request +GET /t +--- response_body +hello +--- wait: 0.1 +--- error_log +API disabled in the context of log_by_lua* + From 82cbbd8334f306d6432dd04edbc98283fb62ca5d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 15 Oct 2013 13:28:48 -0700 Subject: [PATCH 0280/1981] bugfix: subrequests initiated by ngx.location.capture* could trigger unnecessary response header sending actions in the subrequest because our capturing output header filter did not set "r->header_sent". --- src/ngx_http_lua_capturefilter.c | 1 + t/020-subrequest.t | 41 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index 9a945ff80d..8f1e20f02f 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -96,6 +96,7 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) /* force subrequest response body buffer in memory */ r->filter_need_in_memory = 1; + r->header_sent = 1; return NGX_OK; } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index db507ca92c..c3ef047d9c 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -10,7 +10,7 @@ use t::TestNginxLua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 18); +plan tests => repeat_each() * (blocks() * 3 + 19); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -2398,3 +2398,42 @@ 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] + From 70ecf928f8a2af34da00cfd3c924ba7b591b3fb1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 16 Oct 2013 15:26:15 -0700 Subject: [PATCH 0281/1981] docs: fixed the links in the markdown source. now they no longer point to the (broken) nginx wiki site. --- README.markdown | 644 ++++++++++++++++++++++++------------------------ 1 file changed, 322 insertions(+), 322 deletions(-) diff --git a/README.markdown b/README.markdown index 41d1cf308b..20ad6940ff 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ Name ngx_lua - Embed the power of Lua into Nginx -*This module is not distributed with the Nginx source.* See [the installation instructions](http://wiki.nginx.org/HttpLuaModule#Installation). +*This module is not distributed with the Nginx source.* See [the installation instructions](#installation). Status ====== @@ -195,7 +195,7 @@ Description This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. -Unlike [Apache's mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) provided by this module is used to handle +Unlike [Apache's mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: @@ -212,7 +212,7 @@ At least the following Lua libraries and Nginx modules can be used with this ngx * [ngx_proxy](http://wiki.nginx.org/HttpProxyModule) * [ngx_fastcgi](http://wiki.nginx.org/HttpFastcgiModule) -Almost all the Nginx modules can be used with this ngx_lua module by means of [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) or [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) but it is recommended to use those `lua-resty-*` libraries instead of creating subrequests to access the Nginx upstream modules because the former is usually much more flexible and memory-efficient. +Almost all the Nginx modules can be used with this ngx_lua module by means of [ngx.location.capture](#ngxlocationcapture) or [ngx.location.capture_multi](#ngxlocationcapture_multi) but it is recommended to use those `lua-resty-*` libraries instead of creating subrequests to access the Nginx upstream modules because the former is usually much more flexible and memory-efficient. The Lua interpreter or LuaJIT instance is shared across all the requests in a single nginx worker process but request contexts are segregated using lightweight Lua coroutines. @@ -229,27 +229,27 @@ lua_code_cache **context:** *main, server, location, location if* -Enables or disables the Lua code cache for [set_by_lua_file](http://wiki.nginx.org/HttpLuaModule#set_by_lua_file), -[content_by_lua_file](http://wiki.nginx.org/HttpLuaModule#content_by_lua_file), [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file), and -[access_by_lua_file](http://wiki.nginx.org/HttpLuaModule#access_by_lua_file), and also force Lua module reloading on a per-request basis. +Enables or disables the Lua code cache for [set_by_lua_file](#set_by_lua_file), +[content_by_lua_file](#content_by_lua_file), [rewrite_by_lua_file](#rewrite_by_lua_file), and +[access_by_lua_file](#access_by_lua_file), and also force Lua module reloading on a per-request basis. -The Lua files referenced in [set_by_lua_file](http://wiki.nginx.org/HttpLuaModule#set_by_lua_file), -[content_by_lua_file](http://wiki.nginx.org/HttpLuaModule#content_by_lua_file), [access_by_lua_file](http://wiki.nginx.org/HttpLuaModule#access_by_lua_file), -and [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) will not be cached +The Lua files referenced in [set_by_lua_file](#set_by_lua_file), +[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), +and [rewrite_by_lua_file](#rewrite_by_lua_file) will not be cached and the Lua `package.loaded` table will be cleared at the entry point of every request (such that Lua modules will not be cached either). With this in place, developers can adopt an edit-and-refresh approach. Please note however, that Lua code written inlined within nginx.conf -such as those specified by [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua), [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua), -[access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua), and [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) will *always* be +such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), +[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will *always* be cached because only the Nginx config file parser can correctly parse the `nginx.conf` file and the only ways to to reload the config file are to send a `HUP` signal or to restart Nginx. Also, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file will never be cached. To ensure code caching, you can either use the [init_by_lua](http://wiki.nginx.org/HttpLuaModule#init_by_lua) -or [init_by_lua_file](http://wiki.nginx.org/HttpLuaModule#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules +in *_by_lua_file will never be cached. To ensure code caching, you can either use the [init_by_lua](#init_by_lua) +or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules and load them via `require`. The ngx_lua module does not currently support the `stat` mode available with the @@ -271,7 +271,7 @@ lua_regex_cache_max_entries Specifies the maximum number of entries allowed in the worker process level compiled regex cache. -The regular expressions used in [ngx.re.match](http://wiki.nginx.org/HttpLuaModule#ngx.re.match), [ngx.re.gmatch](http://wiki.nginx.org/HttpLuaModule#ngx.re.gmatch), [ngx.re.sub](http://wiki.nginx.org/HttpLuaModule#ngx.re.sub), and [ngx.re.gsub](http://wiki.nginx.org/HttpLuaModule#ngx.re.gsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. +The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: @@ -279,7 +279,7 @@ The default number of entries allowed is 1024 and when this limit is reached, ne 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... -Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](http://wiki.nginx.org/HttpLuaModule#ngx.re.sub) and [ngx.re.gsub](http://wiki.nginx.org/HttpLuaModule#ngx.re.gsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. +Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. lua_regex_match_limit --------------------- @@ -289,9 +289,9 @@ lua_regex_match_limit **context:** *http* -Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](http://wiki.nginx.org/HttpLuaModule#ngx.re.match). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." +Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." -When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](http://wiki.nginx.org/HttpLuaModule#ngx.re.match) functions on the Lua land. +When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. @@ -306,8 +306,8 @@ lua_package_path **context:** *main* -Sets the Lua module search path used by scripts specified by [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua), -[content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) and others. The path string is in standard Lua path form, and `;;` +Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), +[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` can be used to stand for the original search paths. As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. @@ -321,8 +321,8 @@ lua_package_cpath **context:** *main* -Sets the Lua C-module search path used by scripts specified by [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua), -[content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` +Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), +[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` can be used to stand for the original cpath. As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. @@ -354,7 +354,7 @@ Usually you can register (true) Lua global variables or pre-load Lua modules at } -You can also initialize the [lua_shared_dict](http://wiki.nginx.org/HttpLuaModule#lua_shared_dict) shm storage at this phase. Here is an example for this: +You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: lua_shared_dict dogs 1m; @@ -374,14 +374,14 @@ You can also initialize the [lua_shared_dict](http://wiki.nginx.org/HttpLuaModul } -But note that, the [lua_shared_dict](http://wiki.nginx.org/HttpLuaModule#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. +But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. -Only a small set of the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) is supported in this context: +Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: -* Logging APIs: [ngx.log](http://wiki.nginx.org/HttpLuaModule#ngx.log) and [print](http://wiki.nginx.org/HttpLuaModule#print), -* Shared Dictionary API: [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). +* Logging APIs: [ngx.log](#ngxlog) and [print](#print), +* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). More Nginx APIs for Lua may be supported in this context upon future user requests. @@ -400,7 +400,7 @@ init_by_lua_file **phase:** *loading-config* -Equivalent to [init_by_lua](http://wiki.nginx.org/HttpLuaModule#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. @@ -416,19 +416,19 @@ set_by_lua **phase:** *server-rewrite, rewrite* Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. -The code in `` can make [API calls](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). +The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. Note that the following API functions are currently disabled within this context: -* Output API functions (e.g., [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) and [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers)) -* Control API functions (e.g., [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit)) -* Subrequest API functions (e.g., [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket)). +* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) +* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). In addition, note that this directive can only write out a value to a single Nginx variable at -a time. However, a workaround is possible using the [ngx.var.VARIABLE](http://wiki.nginx.org/HttpLuaModule#ngx.var.VARIABLE) interface. +a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. location /foo { @@ -466,7 +466,7 @@ set_by_lua_file **phase:** *server-rewrite, rewrite* -Equivalent to [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. @@ -475,7 +475,7 @@ When a relative path like `foo/bar.lua` is given, they will be turned into the a When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](http://wiki.nginx.org/HttpLuaModule#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. @@ -489,7 +489,7 @@ content_by_lua **phase:** *content* Acts as a "content handler" and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). +The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://wiki.nginx.org/HttpProxyModule#proxy_pass) directive should not be used in the same location. @@ -502,7 +502,7 @@ content_by_lua_file **phase:** *content* -Equivalent to [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [content_by_lua](#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. @@ -511,7 +511,7 @@ When a relative path like `foo/bar.lua` is given, they will be turned into the a When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](http://wiki.nginx.org/HttpLuaModule#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. rewrite_by_lua -------------- @@ -523,7 +523,7 @@ rewrite_by_lua **phase:** *rewrite tail* Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). +The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Note that this handler always runs *after* the standard [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule). So the following will work as expected: @@ -536,7 +536,7 @@ Note that this handler always runs *after* the standard [HttpRewriteModule](http } -because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua). +because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). On the other hand, the following will not work as expected: @@ -554,7 +554,7 @@ On the other hand, the following will not work as expected: ? } -because `if` runs *before* [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) even if it is placed after [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) in the config. +because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. The right way of doing this is as follows: @@ -573,7 +573,7 @@ The right way of doing this is as follows: } -Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua). For example, +Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, location / { @@ -609,11 +609,11 @@ can be implemented in ngx_lua as: } -Just as any other rewrite phase handlers, [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) also runs in subrequests. +Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. -Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) handler, calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. +Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](#rewrite_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. -If the [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule)'s [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) or [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, +If the [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule)'s [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, location /foo { @@ -627,7 +627,7 @@ If the [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule)'s [rewrite]( Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. -The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_no_postpone) is turned on. +The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. rewrite_by_lua_file ------------------- @@ -638,15 +638,15 @@ rewrite_by_lua_file **phase:** *rewrite tail* -Equivalent to [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [rewrite_by_lua](#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](http://wiki.nginx.org/HttpLuaModule#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. -The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_no_postpone) is turned on. +The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. access_by_lua ------------- @@ -658,7 +658,7 @@ access_by_lua **phase:** *access tail* Acts as an access phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). +The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Note that this handler always runs *after* the standard [HttpAccessModule](http://wiki.nginx.org/HttpAccessModule). So the following will work as expected: @@ -678,9 +678,9 @@ Note that this handler always runs *after* the standard [HttpAccessModule](http: } -That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua). +That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). -Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua): +Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](#access_by_lua): location / { @@ -712,9 +712,9 @@ can be implemented in ngx_lua as: } -As with other access phase handlers, [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua) will *not* run in subrequests. +As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. -Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua) handler, calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. +Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. access_by_lua_file ------------------ @@ -725,7 +725,7 @@ access_by_lua_file **phase:** *access tail* -Equivalent to [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [access_by_lua](#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. @@ -733,7 +733,7 @@ When a relative path like `foo/bar.lua` is given, they will be turned into the a When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](http://wiki.nginx.org/HttpLuaModule#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. +The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. header_filter_by_lua -------------------- @@ -748,10 +748,10 @@ Uses Lua code specified in `` to define an output header filter. Note that the following API functions are currently disabled within this context: -* Output API functions (e.g., [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) and [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers)) -* Control API functions (e.g., [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) and [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec)) -* Subrequest API functions (e.g., [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket)). +* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) +* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) +* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) +* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). Here is an example of overriding a response header (or adding one if absent) in our Lua header filter: @@ -773,7 +773,7 @@ header_filter_by_lua_file **phase:** *output-header-filter* -Equivalent to [header_filter_by_lua](http://wiki.nginx.org/HttpLuaModule#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [header_filter_by_lua](#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. @@ -790,7 +790,7 @@ body_filter_by_lua Uses Lua code specified in `` to define an output body filter. -The input data chunk is passed via [ngx.arg](http://wiki.nginx.org/HttpLuaModule#ngx.arg)[1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](http://wiki.nginx.org/HttpLuaModule#ngx.arg)[2] (as a Lua boolean value). +The input data chunk is passed via [ngx.arg](#ngxarg)[1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)[2] (as a Lua boolean value). Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) @@ -802,7 +802,7 @@ The output data stream can be aborted immediately by running the following Lua s This will truncate the response body and usually result in incomplete and also invalid responses. -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](http://wiki.nginx.org/HttpLuaModule#ngx.arg)[1] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: +The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)[1] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: location / { @@ -813,7 +813,7 @@ The Lua code can pass its own modified version of the input data chunk to the do When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](http://wiki.nginx.org/HttpLuaModule#ngx.arg)[2]. For example, +Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)[2]. For example, location /t { @@ -854,10 +854,10 @@ When the Lua code may change the length of the response body, then it is require Note that the following API functions are currently disabled within this context: -* Output API functions (e.g., [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) and [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers)) -* Control API functions (e.g., [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) and [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec)) -* Subrequest API functions (e.g., [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket)). +* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) +* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) +* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) +* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request. @@ -872,7 +872,7 @@ body_filter_by_lua_file **phase:** *output-body-filter* -Equivalent to [body_filter_by_lua](http://wiki.nginx.org/HttpLuaModule#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [body_filter_by_lua](#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. @@ -891,10 +891,10 @@ Run the Lua source code inlined as the `` at the `log` request p Note that the following API functions are currently disabled within this context: -* Output API functions (e.g., [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say) and [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers)) -* Control API functions (e.g., [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit)) -* Subrequest API functions (e.g., [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp) and [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket)). +* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) +* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). Here is an example of gathering average data for [$upstream_response_time](http://wiki.nginx.org/HttpUpstreamModule#.24upstream_response_time): @@ -949,7 +949,7 @@ log_by_lua_file **phase:** *log* -Equivalent to [log_by_lua](http://wiki.nginx.org/HttpLuaModule#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](http://wiki.nginx.org/HttpLuaModule#Lua/LuaJIT_bytecode_support) to be executed. +Equivalent to [log_by_lua](#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. @@ -966,20 +966,20 @@ lua_need_request_body **phase:** *depends on usage* -Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) function should be called within the Lua code. +Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. To read the request body data within the [$request_body](http://wiki.nginx.org/HttpCoreModule#.24request_body) variable, [client_body_buffer_size](http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size) must have the same value as [client_max_body_size](http://wiki.nginx.org/HttpCoreModule#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size) but less than [client_max_body_size](http://wiki.nginx.org/HttpCoreModule#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://wiki.nginx.org/HttpCoreModule#.24request_body) variable. -If the current location includes [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) or [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) directives, -then the request body will be read just before the [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) or [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) code is run (and also at the -`rewrite` phase). Similarly, if only [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) is specified, +If the current location includes [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) directives, +then the request body will be read just before the [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code is run (and also at the +`rewrite` phase). Similarly, if only [content_by_lua](#content_by_lua) is specified, the request body will not be read until the content handler's Lua code is about to run (i.e., the request body will be read during the content phase). -It is recommended however, to use the [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) and [ngx.req.discard_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.discard_body) functions for finer control over the request body reading process instead. +It is recommended however, to use the [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body) functions for finer control over the request body reading process instead. -This also applies to [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua) and [access_by_lua_file](http://wiki.nginx.org/HttpLuaModule#access_by_lua_file). +This also applies to [access_by_lua](#access_by_lua) and [access_by_lua_file](#access_by_lua_file). lua_shared_dict --------------- @@ -1003,7 +1003,7 @@ The `` argument accepts size units such as `k` and `m`: } -See [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) for details. +See [ngx.shared.DICT](#ngxshareddict) for details. This directive was first introduced in the `v0.3.1rc22` release. @@ -1016,7 +1016,7 @@ lua_socket_connect_timeout **context:** *http, server, location* -This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](http://wiki.nginx.org/HttpLuaModule#tcpsock:connect) method and can be overridden by the [settimeout](http://wiki.nginx.org/HttpLuaModule#tcpsock:settimeout) method. +This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](#tcpsockconnect) method and can be overridden by the [settimeout](#tcpsocksettimeout) method. The ` -: instead of the old deprecated form: +instead of the old deprecated form: require('xxx') @@ -5234,6 +5236,7 @@ Care must be taken when importing modules and this form should be used: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the require() built-in in the package.loaded table for later reference, and require() has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the nil value. Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because + # misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, # Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and # some Lua global variable references are just typos, which are hard to debug. From 1d85a61f6461325ad42adaa3d33b5c4cbd4a7682 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 23 Jan 2014 19:18:24 -0800 Subject: [PATCH 0453/1981] doc: mentioned ngx.timer.at for doing background jobs in ngx.eof's documentation. --- README.markdown | 2 ++ doc/HttpLuaModule.wiki | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.markdown b/README.markdown index 171357c640..5e21bac80a 100644 --- a/README.markdown +++ b/README.markdown @@ -3613,6 +3613,8 @@ But if you create subrequests to access other locations configured by Nginx upst proxy_ignore_client_abort on; ``` +A better way to do background jobs is to use the [ngx.timer.at](#ngxtimerat) API. + Since `v0.8.3` this function returns `1` on success, or returns `nil` and a string describing the error otherwise. [Back to TOC](#table-of-contents) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index ae93a7b251..f57c00131c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3004,6 +3004,8 @@ But if you create subrequests to access other locations configured by Nginx upst proxy_ignore_client_abort on; +A better way to do background jobs is to use the [[#ngx.timer.at|ngx.timer.at]] API. + Since v0.8.3 this function returns 1 on success, or returns nil and a string describing the error otherwise. == ngx.sleep == From c005354029733c947012bbc74fca40451ce7ffd0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 25 Jan 2014 13:54:24 -0800 Subject: [PATCH 0454/1981] bugfix: timers created by ngx.timer.at() might not be aborted prematurely upon nginx worker exit. thanks Hamish Forbes for the report. --- src/ngx_http_lua_timer.c | 12 ++- t/109-timer-hup.t | 162 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 171 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 00e221bc9a..8afc1c09e7 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -462,8 +462,8 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) sentinel = ngx_event_timer_rbtree.sentinel; - prev = NULL; cur = ngx_event_timer_rbtree.root; + prev = cur->parent; events = ngx_pcalloc(ngx_cycle->pool, lmcf->pending_timers * sizeof(ngx_event_t)); @@ -475,7 +475,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) dd("root: %p, root parent: %p, sentinel: %p", cur, cur->parent, sentinel); - while (lmcf->pending_timers > n) { + while (n < lmcf->pending_timers) { if (cur == sentinel || cur == NULL) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "lua pending timer counter got out of sync: %i", @@ -483,6 +483,9 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) break; } + dd("prev: %p, cur: %p, cur parent: %p, cur left: %p, cur right: %p", + prev, cur, cur->parent, cur->left, cur->right); + if (prev == cur->parent) { next = cur->left; if (next == sentinel) { @@ -519,6 +522,10 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) cur = next; } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua found %i pending timers to be aborted prematurely", + n); + for (i = 0; i < n; i++) { ev = events[i]; @@ -537,6 +544,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) tctx = ev->data; tctx->premature = 1; + dd("calling timer handler prematurely"); ev->handler(ev); } diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 99f3b00985..e62b5e7336 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -28,7 +28,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * 60; +plan tests => repeat_each() * 76; #no_diff(); no_long_string(); @@ -279,3 +279,163 @@ f: exiting=true g: timer prematurely expired: false g: exiting=true + + +=== TEST 5: HUP reload should abort pending timers +--- config + location /t { + content_by_lua ' + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + + f:close() + + local function f(premature) + print("f: timer prematurely expired: ", premature) + print("f: exiting=", ngx.worker.exiting()) + end + + for i = 1, 100 do + local ok, err = ngx.timer.at(3 + i, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + ngx.say("ok") + os.execute("kill -HUP " .. pid) + '; + } +--- request +GET /t + +--- response_body +ok + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +in callback: hello, 2 +failed to register a new timer after reload + +--- grep_error_log eval: qr/lua found \d+ pending timers/ +--- grep_error_log_out +lua found 100 pending timers + + + +=== TEST 6: HUP reload should abort pending timers (coroutine + cosocket) +--- http_config + lua_shared_dict test_dict 1m; + + server { + listen 54123; + location = /foo { + echo 'foo'; + } + } + +--- config + location /t { + content_by_lua ' + local http_req = {"GET /foo HTTP/1.1", "Host: localhost:1234", "", ""} + http_req = table.concat(http_req, "\\r\\n") + + -- Connect the socket + local sock = ngx.socket.tcp() + local ok,err = sock:connect("127.0.0.1", 54123) + if not ok then + ngx.log(ngx.ERR, err) + end + + -- Send the request + local ok,err = sock:send(http_req) + + -- Get Headers + repeat + local line, err = sock:receive("*l") + until string.find(line, "^%s*$") + + function foo() + repeat + -- Get and read chunk + local line, err = sock:receive("*l") + local len = tonumber(line) + if len > 0 then + local chunk, err = sock:receive(len) + coroutine.yield(chunk) + sock:receive(2) + else + -- Read last newline + sock:receive(2) + end + until len == 0 + end + + co = coroutine.create(foo) + repeat + local chunk = select(2,coroutine.resume(co)) + until chunk == nil + + -- Breaks the timer + sock:setkeepalive() + ngx.say("ok") + '; + + log_by_lua ' + local background_thread + background_thread = function(premature) + ngx.log(ngx.DEBUG, premature) + if premature then + ngx.shared["test_dict"]:delete("background_flag") + return + end + local ok, err = ngx.timer.at(1, background_thread) + + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + f:close() + + os.execute("kill -HUP " .. pid) + end + local dict = ngx.shared["test_dict"] + + if dict:get("background_flag") == nil then + local ok, err = ngx.timer.at(0, background_thread) + if ok then + dict:set("test_dict", 1) + end + end + '; + } +--- request +GET /t + +--- response_body +ok + +--- wait: 0.3 +--- no_error_log +[error] +[alert] +[crit] +in callback: hello, 2 +failed to register a new timer after reload + +--- grep_error_log eval: qr/lua found \d+ pending timers/ +--- grep_error_log_out +lua found 1 pending timers + From 47836cec1689a4f35559904c7dd2456e6dcb5a5b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 25 Jan 2014 15:35:49 -0800 Subject: [PATCH 0455/1981] bugfix: segmentation faults might happen when multiple "light threads" in the same request manipuate a stream cosocket object in turn. thanks Aviram Cohen for the report. --- src/ngx_http_lua_sleep.c | 3 +- src/ngx_http_lua_socket_tcp.c | 34 +++++++------ t/058-tcp-socket.t | 95 ++++++++++++++++++++++++++++++++++- 3 files changed, 113 insertions(+), 19 deletions(-) diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 0acd89d86e..0d5cb7f322 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -138,7 +138,8 @@ ngx_http_lua_sleep_cleanup(void *data) ngx_http_lua_co_ctx_t *coctx = data; if (coctx->sleep.timer_set) { - dd("cleanup: deleting timer for ngx.sleep"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua clean up the timer for pending ngx.sleep"); ngx_del_timer(&coctx->sleep); } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index eef0033b5c..097904c370 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -800,6 +800,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) ngx_resolve_name_done(ctx); u->waiting = 0; + u->co_ctx = NULL; if (waiting) { lctx->resume_handler = ngx_http_lua_socket_tcp_resume; @@ -1233,6 +1234,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) } u->waiting = 0; + u->co_ctx = NULL; rc = ngx_http_lua_socket_tcp_read(r, u); @@ -1835,6 +1837,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L) #if 1 u->waiting = 0; + u->co_ctx = NULL; #endif ngx_http_lua_probe_socket_tcp_send_start(r, u, b->pos, len); @@ -2281,32 +2284,28 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) { ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; #if 1 u->read_event_handler = ngx_http_lua_socket_dummy_handler; u->write_event_handler = ngx_http_lua_socket_dummy_handler; #endif - if (u->co_ctx) { - u->co_ctx->cleanup = NULL; - } - -#if 0 - if (u->eof) { - ngx_http_lua_socket_tcp_finalize(r, u); - } -#endif - if (u->waiting) { u->waiting = 0; + ngx_http_lua_assert(u->co_ctx != NULL); + coctx = u->co_ctx; + coctx->cleanup = NULL; + u->co_ctx = NULL; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return; } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; - ctx->cur_co_ctx = u->co_ctx; + ctx->cur_co_ctx = coctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2321,6 +2320,7 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, ngx_uint_t ft_type) { ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket handle error"); @@ -2331,23 +2331,24 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_finalize(r, u); #endif - if (u->co_ctx) { - u->co_ctx->cleanup = NULL; - } - u->read_event_handler = ngx_http_lua_socket_dummy_handler; u->write_event_handler = ngx_http_lua_socket_dummy_handler; if (u->waiting) { u->waiting = 0; + ngx_http_lua_assert(u->co_ctx != NULL); + coctx = u->co_ctx; + coctx->cleanup = NULL; + u->co_ctx = NULL; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return; } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; - ctx->cur_co_ctx = u->co_ctx; + ctx->cur_co_ctx = coctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2792,6 +2793,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) } u->waiting = 0; + u->co_ctx = NULL; rc = ngx_http_lua_socket_tcp_read(r, u); diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 6455d1116e..1036404529 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 126; +plan tests => repeat_each() * 130; our $HtmlDir = html_dir; @@ -15,7 +15,7 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; #log_level 'warn'; log_level 'debug'; -#no_long_string(); +no_long_string(); #no_diff(); run_tests(); @@ -2575,3 +2575,94 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 42: u->coctx left over bug +--- config + server_tokens off; + location = /t { + #set $port 5000; + set $port $TEST_NGINX_SERVER_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + local port = ngx.var.port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent: ", bytes) + + local ready = false + local fatal = false + + function f() + local line, err, part = sock:receive() + if not line then + ngx.say("failed to receive the 1st line: ", err, " [", part, "]") + fatal = true + return + end + ready = true + ngx.sleep(1) + end + + local st = ngx.thread.spawn(f) + while true do + if fatal then + return + end + + if not ready then + ngx.sleep(0.01) + else + break + end + end + + while true do + local line, err, part = sock:receive() + if line then + -- ngx.say("received: ", line) + + else + -- ngx.say("failed to receive a line: ", err, " [", part, "]") + break + end + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + ngx.exit(0) + '; + } + + location /foo { + content_by_lua 'ngx.sleep(0.1) ngx.say("foo")'; + more_clear_headers Date; + } + +--- request +GET /t +--- response_body +connected: 1 +request sent: 57 +close: nil closed +--- no_error_log +[error] +--- error_log +lua clean up the timer for pending ngx.sleep + From 2079446fae31b6f1ed2be319b5310921c85b1f54 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 13:06:33 -0800 Subject: [PATCH 0456/1981] bugfix: use of the public C API in other nginx C modules (extending ngx_lua) lead to compilation errors and warnings when the Microsoft C compiler is used. thanks Edwin Cleton for the report. --- src/api/ngx_http_lua_api.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 2a5316c2c0..c61ffe2a80 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -13,6 +13,7 @@ #include #include +#include /* Public API for other Nginx modules */ From 870b9a7f16845878ace78e4e8509e8f3fc35b846 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 14:06:06 -0800 Subject: [PATCH 0457/1981] test: use smaller port numbers to reduce the chance of conflicting with local ports. --- t/014-bugs.t | 4 ++-- t/109-timer-hup.t | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index 4ec47a8ec0..0d24ca466c 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -849,7 +849,7 @@ GET /t --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua'; server { - listen 54123; + listen 12354; location = /t { echo 'args: \$args'; @@ -859,7 +859,7 @@ GET /t --- config location = /t { set $args "foo=1&bar=2"; - proxy_pass http://127.0.0.1:54123; + proxy_pass http://127.0.0.1:12354; } --- request diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index e62b5e7336..98e9cb1e6b 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -337,7 +337,7 @@ lua found 100 pending timers lua_shared_dict test_dict 1m; server { - listen 54123; + listen 12355; location = /foo { echo 'foo'; } @@ -351,7 +351,7 @@ lua found 100 pending timers -- Connect the socket local sock = ngx.socket.tcp() - local ok,err = sock:connect("127.0.0.1", 54123) + local ok,err = sock:connect("127.0.0.1", 12355) if not ok then ngx.log(ngx.ERR, err) end From 096e2ff8ed27e6bf078d17fb78a7121920991515 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 17:58:43 -0800 Subject: [PATCH 0458/1981] doc: updated the "TODO" section to reflect recent changes. --- README.markdown | 5 ----- doc/HttpLuaModule.wiki | 5 ----- 2 files changed, 10 deletions(-) diff --git a/README.markdown b/README.markdown index 5e21bac80a..cb6994c127 100644 --- a/README.markdown +++ b/README.markdown @@ -6477,23 +6477,18 @@ TODO Short Term ---------- -* review and apply Brian Akin's patch for the new directive `lua_socket_log_errors`. -* review and apply Brian Akin's patch for the new `shdict:flush_expired()` API. * implement the SSL cosocket API. * review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. -* add APIs to access cookies as key/value pairs. * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. -* implement new directive `lua_ignore_client_abort`. [Back to TOC](#table-of-contents) Longer Term ----------- -* add lightweight thread API (i.e., the `ngx.thread` API) as demonstrated in [this sample code](http://agentzh.org/misc/nginx/lua-thread2.lua). * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f57c00131c..1e5b0d9490 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5484,20 +5484,15 @@ Please submit bug reports, wishlists, or patches by = TODO = == Short Term == -* review and apply Brian Akin's patch for the new directive lua_socket_log_errors. -* review and apply Brian Akin's patch for the new shdict:flush_expired() API. * implement the SSL cosocket API. * review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. * add directives to run Lua codes when nginx stops. -* add APIs to access cookies as key/value pairs. * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. -* implement new directive lua_ignore_client_abort. == Longer Term == -* add lightweight thread API (i.e., the ngx.thread API) as demonstrated in [http://agentzh.org/misc/nginx/lua-thread2.lua this sample code]. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [http://httpd.apache.org/docs/2.3/mod/mod_lua.html mod_lua]. From 2c4534ab264b132d7e770114615b380ed69eeb94 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 18:02:11 -0800 Subject: [PATCH 0459/1981] test: now we require the ngx_lua_upstream module for the test suite. --- README.markdown | 1 + doc/HttpLuaModule.wiki | 1 + util/build2.sh | 1 + 3 files changed, 3 insertions(+) diff --git a/README.markdown b/README.markdown index cb6994c127..5910518895 100644 --- a/README.markdown +++ b/README.markdown @@ -6521,6 +6521,7 @@ The following dependencies are required to run the test suite: * [ngx_memc](http://github.com/agentzh/memc-nginx-module) * [ngx_srcache](http://github.com/agentzh/srcache-nginx-module) * ngx_lua (i.e., this module) + * [ngx_lua_upstream](http://github.com/agentzh/lua-upstream-nginx-module) * [ngx_headers_more](http://github.com/agentzh/headers-more-nginx-module) * [ngx_drizzle](http://github.com/chaoslawful/drizzle-nginx-module) * [ngx_rds_json](http://github.com/agentzh/rds-json-nginx-module) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 1e5b0d9490..dd29507705 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5519,6 +5519,7 @@ The following dependencies are required to run the test suite: ** [http://github.com/agentzh/memc-nginx-module ngx_memc] ** [http://github.com/agentzh/srcache-nginx-module ngx_srcache] ** ngx_lua (i.e., this module) +** [http://github.com/agentzh/lua-upstream-nginx-module ngx_lua_upstream] ** [http://github.com/agentzh/headers-more-nginx-module ngx_headers_more] ** [http://github.com/chaoslawful/drizzle-nginx-module ngx_drizzle] ** [http://github.com/agentzh/rds-json-nginx-module ngx_rds_json] diff --git a/util/build2.sh b/util/build2.sh index 99ea28a51e..4643dddd7d 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -39,6 +39,7 @@ time ngx-build $force $version \ --add-module=$root/../memc-nginx-module \ --add-module=$root/../srcache-nginx-module \ --add-module=$root \ + --add-module=$root/../lua-upstream-nginx-module \ --add-module=$root/../headers-more-nginx-module \ --add-module=$root/../drizzle-nginx-module \ --add-module=$root/../rds-json-nginx-module \ From 6525ec0d013530ab5c66f646377c0d318da26856 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 21:35:49 -0800 Subject: [PATCH 0460/1981] change: turned off lua_socket_log_errors in init_worker_by_lua*. --- src/ngx_http_lua_initworkerby.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 6e90591efc..d9e678f2b7 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -30,6 +30,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_conf_ctx_t *conf_ctx, http_ctx; + ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; @@ -153,6 +154,9 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ctx->cur_co_ctx = NULL; r->read_event_handler = ngx_http_block_reading; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + llcf->log_socket_errors = 0; + ngx_http_lua_set_req(lmcf->lua, r); (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); From a6e0f512e0faeadfe32eb266aed06a8f4a00ef9c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 21:54:48 -0800 Subject: [PATCH 0461/1981] reindexed the tests in t/058-tcp-socket.t. --- t/058-tcp-socket.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 1036404529..41b7ee5b79 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -2577,7 +2577,7 @@ close: 1 nil -=== TEST 42: u->coctx left over bug +=== TEST 43: u->coctx left over bug --- config server_tokens off; location = /t { From 92219bba5e9c7f27538d9929c9ba6561da06ccee Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 26 Jan 2014 21:55:17 -0800 Subject: [PATCH 0462/1981] feature: added new API function ngx.worker.pid() for retrieving the current nginx worker process's pid. --- src/ngx_http_lua_worker.c | 12 +++++++++ t/122-worker.t | 51 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_worker.c b/src/ngx_http_lua_worker.c index f5b732fce5..9937361b25 100644 --- a/src/ngx_http_lua_worker.c +++ b/src/ngx_http_lua_worker.c @@ -14,6 +14,7 @@ static int ngx_http_lua_ngx_worker_exiting(lua_State *L); +static int ngx_http_lua_ngx_worker_pid(lua_State *L); void @@ -24,6 +25,9 @@ ngx_http_lua_inject_worker_api(lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_worker_exiting); lua_setfield(L, -2, "exiting"); + lua_pushcfunction(L, ngx_http_lua_ngx_worker_pid); + lua_setfield(L, -2, "pid"); + lua_setfield(L, -2, "worker"); } @@ -34,3 +38,11 @@ ngx_http_lua_ngx_worker_exiting(lua_State *L) lua_pushboolean(L, ngx_exiting); return 1; } + + +static int +ngx_http_lua_ngx_worker_pid(lua_State *L) +{ + lua_pushinteger(L, (lua_Integer) ngx_pid); + return 1; +} diff --git a/t/122-worker.t b/t/122-worker.t index f585668e08..fa42b1d9ad 100644 --- a/t/122-worker.t +++ b/t/122-worker.t @@ -17,7 +17,7 @@ run_tests(); __DATA__ -=== TEST 1: content_by_lua +=== TEST 1: content_by_lua + ngx.worker.exiting --- config location /lua { content_by_lua ' @@ -31,3 +31,52 @@ worker exiting: false --- no_error_log [error] + + +=== TEST 2: content_by_lua + ngx.worker.pid +--- config + location /lua { + content_by_lua ' + local pid = ngx.worker.pid() + ngx.say("worker pid: ", pid) + if pid ~= tonumber(ngx.var.pid) then + ngx.say("worker pid is wrong.") + else + ngx.say("worker pid is correct.") + end + '; + } +--- request +GET /lua +--- response_body_like +worker pid: \d+ +worker pid is correct\. +--- no_error_log +[error] + + + +=== TEST 3: init_worker_by_lua + ngx.worker.pid +--- http_config + init_worker_by_lua ' + my_pid = ngx.worker.pid() + '; +--- config + location /lua { + content_by_lua ' + ngx.say("worker pid: ", my_pid) + if my_pid ~= tonumber(ngx.var.pid) then + ngx.say("worker pid is wrong.") + else + ngx.say("worker pid is correct.") + end + '; + } +--- request +GET /lua +--- response_body_like +worker pid: \d+ +worker pid is correct\. +--- no_error_log +[error] + From a1c15f46bb32c1947dae2efddc8966b82827e077 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 27 Jan 2014 14:27:40 -0800 Subject: [PATCH 0463/1981] fixed an erorr message in ngx_http_lua_report. --- src/ngx_http_lua_util.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index c5328578ba..6dd683c570 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -3952,8 +3952,7 @@ ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status) msg = "unknown error"; } - ngx_log_error(NGX_LOG_ERR, log, 0, "failed to run init_by_lua*: %s", - msg); + ngx_log_error(NGX_LOG_ERR, log, 0, "%s", msg); lua_pop(L, 1); } From 3eafa8df140e7610f20dca9b1407e356cb7d59ba Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 27 Jan 2014 14:41:04 -0800 Subject: [PATCH 0464/1981] better context info in the error messages for init_by_lua* and init_worker_by_lua*. --- src/ngx_http_lua_initby.c | 4 ++-- src/ngx_http_lua_initworkerby.c | 4 ++-- src/ngx_http_lua_util.c | 5 +++-- src/ngx_http_lua_util.h | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index d68df85a6e..4293f93306 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -23,7 +23,7 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lmcf->init_src.len, "init_by_lua") || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status); + return ngx_http_lua_report(log, L, status, "init_by_lua"); } @@ -36,7 +36,7 @@ ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, status = luaL_loadfile(L, (char *) lmcf->init_src.data) || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status); + return ngx_http_lua_report(log, L, status, "init_by_lua_file"); } /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index d9e678f2b7..7fefb2b557 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -193,7 +193,7 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, lmcf->init_worker_src.len, "init_worker_by_lua") || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status); + return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); } @@ -206,7 +206,7 @@ ngx_http_lua_init_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data) || ngx_http_lua_do_call(log, L); - return ngx_http_lua_report(log, L, status); + return ngx_http_lua_report(log, L, status, "init_worker_by_lua_file"); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 6dd683c570..7d4f2bf00b 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -3942,7 +3942,8 @@ ngx_http_lua_create_fake_request(ngx_connection_t *c) ngx_int_t -ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status) +ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status, + const char *prefix) { const char *msg; @@ -3952,7 +3953,7 @@ ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status) msg = "unknown error"; } - ngx_log_error(NGX_LOG_ERR, log, 0, "%s", msg); + ngx_log_error(NGX_LOG_ERR, log, 0, "%s error: %s", prefix, msg); lua_pop(L, 1); } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index d943935307..53dc8a0fe0 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -219,7 +219,8 @@ ngx_connection_t * ngx_http_lua_create_fake_connection(void); ngx_http_request_t * ngx_http_lua_create_fake_request(ngx_connection_t *c); -ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status); +ngx_int_t ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status, + const char *prefix); int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L); From 7668963788640a7d63bb2d25943b6082f0ced29c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 27 Jan 2014 15:25:38 -0800 Subject: [PATCH 0465/1981] skipped tests that could fail in the "check leak" testing mode. --- t/014-bugs.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/014-bugs.t b/t/014-bugs.t index 0d24ca466c..a7be5d98c6 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -383,6 +383,7 @@ It works! --- response_body status = 301 Location: /foo/ +--- no_check_leak @@ -697,6 +698,7 @@ Content-Type: application/json; charset=utf-8 === TEST 32: hang on upstream_next (from kindy) +--- no_check_leak --- http_config upstream xx { server 127.0.0.1:$TEST_NGINX_SERVER_PORT max_fails=5; @@ -868,4 +870,5 @@ GET /t args: foo=1&bar=2 --- no_error_log [error] +--- no_check_leak From 4112e749d6ad80b2ecd54d5f9fddc32b830b12fe Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 31 Jan 2014 22:14:59 -0800 Subject: [PATCH 0466/1981] bugfix: fixed the error message buffer overwrite in the C API for FFI-based ngx.re implementations. --- src/ngx_http_lua_regex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index dce268ec23..7da2451339 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2125,7 +2125,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, re_comp.options = pcre_opts; re_comp.pattern.data = (u_char *) pat; re_comp.pattern.len = pat_len; - re_comp.err.len = errstr_size; + re_comp.err.len = errstr_size - 1; re_comp.err.data = errstr; re_comp.pool = pool; From e5c1105beed546cddcffce295e1bb7f38905be1a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 31 Jan 2014 22:17:34 -0800 Subject: [PATCH 0467/1981] bugfix: fixes for small string buffer arguments in the C API for FFI-based implementations of shdict:get(). --- src/ngx_http_lua_shdict.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 9d4bedbfa5..13fdbbee23 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1666,21 +1666,23 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, value.len = (size_t) sd->value_len; if (*str_value_len < (size_t) value.len) { - if (*value_type != LUA_TSTRING) { + if (*value_type == LUA_TBOOLEAN) { + ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } - *str_value_buf = malloc(value.len); - if (*str_value_buf == NULL) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - return NGX_ERROR; + if (*value_type == LUA_TSTRING) { + *str_value_buf = malloc(value.len); + if (*str_value_buf == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } } } - *str_value_len = value.len; - switch (*value_type) { case LUA_TSTRING: + *str_value_len = value.len; ngx_memcpy(*str_value_buf, value.data, value.len); break; @@ -1695,6 +1697,7 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, return NGX_ERROR; } + *str_value_len = value.len; *num_value = *(double *) value.data; break; From 7460a8d16cc406fa3ba3fc33c6aa8f1be409d30b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 1 Feb 2014 10:51:10 -0800 Subject: [PATCH 0468/1981] adjusted a test case that could fail on slow machines. --- t/107-timer-errors.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t index 98a7400f2c..d13c6d875e 100644 --- a/t/107-timer-errors.t +++ b/t/107-timer-errors.t @@ -1290,7 +1290,7 @@ F(ngx_http_lua_timer_handler) { --- response_body registered timer ---- wait: 0.1 +--- wait: 0.2 --- no_error_log [alert] [crit] From df7bf56af95d4564e20d8b893aa50d7b26a5d3e1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 5 Feb 2014 12:25:59 -0800 Subject: [PATCH 0469/1981] doc: documented the new ngx.worker.pid() API. --- README.markdown | 14 ++++++++++++++ doc/HttpLuaModule.wiki | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/README.markdown b/README.markdown index 5910518895..5d8a5ed36e 100644 --- a/README.markdown +++ b/README.markdown @@ -173,6 +173,7 @@ Table of Contents * [ngx.config.nginx_version](#ngxconfignginx_version) * [ngx.config.ngx_lua_version](#ngxconfigngx_lua_version) * [ngx.worker.exiting](#ngxworkerexiting) + * [ngx.worker.pid](#ngxworkerpid) * [ndk.set_var.DIRECTIVE](#ndkset_vardirective) * [coroutine.create](#coroutinecreate) * [coroutine.resume](#coroutineresume) @@ -5793,6 +5794,19 @@ This API was first introduced in the `0.9.3` release. [Back to TOC](#table-of-contents) +ngx.worker.pid +-------------- + +**syntax:** *pid = ngx.worker.pid()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua** + +This function returns a Lua number for the process ID (PID) of the current Nginx worker process. This API is more efficient than `ngx.var.pid` and can be used in contexts where the [ngx.var.VARIABLE](#ngxvarvariable) API cannot be used (like [init_worker_by_lua](#init_worker_by_lua)). + +This API was first introduced in the `0.9.5` release. + +[Back to TOC](#table-of-contents) + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index dd29507705..205813f6f0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4919,6 +4919,16 @@ This function returns a boolean value indicating whether the current Nginx worke This API was first introduced in the 0.9.3 release. +== ngx.worker.pid == + +'''syntax:''' ''pid = ngx.worker.pid()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*'' + +This function returns a Lua number for the process ID (PID) of the current Nginx worker process. This API is more efficient than ngx.var.pid and can be used in contexts where the [[#ngx.var.VARIABLE|ngx.var.VARIABLE]] API cannot be used (like [[#init_worker_by_lua|init_worker_by_lua]]). + +This API was first introduced in the 0.9.5 release. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' From ec368b46fcb1d21af91dc1c093d3d581a1feb741 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 6 Feb 2014 16:45:52 -0800 Subject: [PATCH 0470/1981] refactor: removed an unused parameter, "len", in ngx_http_lua_ffi_script_eval_data. --- src/ngx_http_lua_regex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 7da2451339..2a1b8df679 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2410,7 +2410,7 @@ ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, void ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, - ngx_http_lua_complex_value_t *val, u_char *dst, size_t len) + ngx_http_lua_complex_value_t *val, u_char *dst) { ngx_http_lua_script_code_pt code; From f7db5fddb8c55fcf1274ef0bb5f5795125cd8c35 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 13 Feb 2014 12:10:42 -0800 Subject: [PATCH 0471/1981] doc: fixed linkrot of mod_lua. thanks Tatsuhiko Kubo for the patch in #336. --- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 5d8a5ed36e..71d08c577a 100644 --- a/README.markdown +++ b/README.markdown @@ -399,7 +399,7 @@ Description This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. -Unlike [Apache's mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle +Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: @@ -6504,7 +6504,7 @@ Short Term Longer Term ----------- * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. -* add `stat` mode similar to [mod_lua](http://httpd.apache.org/docs/2.3/mod/mod_lua.html). +* add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). [Back to TOC](#table-of-contents) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 205813f6f0..4392e6b653 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -185,7 +185,7 @@ This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module This module embeds Lua, via the standard Lua 5.1 interpreter or [http://luajit.org/luajit.html LuaJIT 2.0/2.1], into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. -Unlike [http://httpd.apache.org/docs/2.3/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle +Unlike [https://httpd.apache.org/docs/trunk/mod/mod_lua.html Apache's mod_lua] and [http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet Lighttpd's mod_magnet], Lua code executed using this module can be ''100% non-blocking'' on network traffic as long as the [[#Nginx API for Lua|Nginx API for Lua]] provided by this module is used to handle requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: @@ -5504,7 +5504,7 @@ Please submit bug reports, wishlists, or patches by == Longer Term == * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. -* add stat mode similar to [http://httpd.apache.org/docs/2.3/mod/mod_lua.html mod_lua]. +* add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. = Changes = From eab56942ac3df391b5477e75338f3e4596ce2ea1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 18 Feb 2014 12:04:32 -0800 Subject: [PATCH 0472/1981] doc: fixed a typo in the doc for coroutine.yield(). thanks Ruoshan Huang for the report. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 71d08c577a..b9ea535a63 100644 --- a/README.markdown +++ b/README.markdown @@ -5882,7 +5882,7 @@ This API was first introduced in the `v0.6.0` release. coroutine.yield --------------- -**syntax:** *... = coroutine.yield(co, ...)* +**syntax:** *... = coroutine.yield(...)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.** diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 4392e6b653..2b9123765f 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4993,7 +4993,7 @@ This API was first usable in the context of [[#init_by_lua|init_by_lua*]] since This API was first introduced in the v0.6.0 release. == coroutine.yield == -'''syntax:''' ''... = coroutine.yield(co, ...)'' +'''syntax:''' ''... = coroutine.yield(...)'' '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*'' From 4a0036c0746e62666e5de27147a6b3c33c8dc7c9 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 26 Feb 2014 14:18:09 -0800 Subject: [PATCH 0473/1981] optimize: coroutine status string look-up is now a bit more efficient by specifying the string lengths explicitly. thanks Tatsuhiko Kubo for the patch in #338. --- src/ngx_http_lua_coroutine.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index ec7d3e8cff..d9624cd93c 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -30,9 +30,15 @@ static int ngx_http_lua_coroutine_yield(lua_State *L); static int ngx_http_lua_coroutine_status(lua_State *L); -static const char * +static const ngx_str_t ngx_http_lua_co_status_names[] = - {"running", "suspended", "normal", "dead", "zombie"}; + { + ngx_string("running"), + ngx_string("suspended"), + ngx_string("normal"), + ngx_string("dead"), + ngx_string("zombie") + }; @@ -160,7 +166,7 @@ ngx_http_lua_coroutine_resume(lua_State *L) lua_pushboolean(L, 0); lua_pushfstring(L, "cannot resume %s coroutine", - ngx_http_lua_co_status_names[coctx->co_status]); + ngx_http_lua_co_status_names[coctx->co_status].data); return 2; } @@ -345,13 +351,17 @@ ngx_http_lua_coroutine_status(lua_State *L) coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { - lua_pushstring(L, ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD]); + lua_pushlstring(L, (const char *) + ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].data, + ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].len); return 1; } dd("co status: %d", coctx->co_status); - lua_pushstring(L, ngx_http_lua_co_status_names[coctx->co_status]); + lua_pushlstring(L, (const char *) + ngx_http_lua_co_status_names[coctx->co_status].data, + ngx_http_lua_co_status_names[coctx->co_status].len); return 1; } From 887f0f99d54d07f78ebbdcd2289de17fb515c05d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 26 Feb 2014 15:14:09 -0800 Subject: [PATCH 0474/1981] feature: added new API function ngx.resp.get_headers() for fetching all the response headers. thanks Tatsuhiko Kubo for the patch in #335. --- src/ngx_http_lua_headers.c | 164 +++++++++++++++++++++++++++++++++---- src/ngx_http_lua_headers.h | 3 +- src/ngx_http_lua_util.c | 7 +- src/ngx_http_lua_util.h | 4 +- t/016-resp-header.t | 82 ++++++++++++++++++- t/062-count.t | 8 +- 6 files changed, 241 insertions(+), 27 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index d52e440041..55c6efc932 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -25,6 +25,7 @@ static int ngx_http_lua_ngx_header_set(lua_State *L); static int ngx_http_lua_ngx_req_get_headers(lua_State *L); static int ngx_http_lua_ngx_req_header_clear(lua_State *L); static int ngx_http_lua_ngx_req_header_set(lua_State *L); +static int ngx_http_lua_ngx_resp_get_headers(lua_State *L); static int @@ -338,7 +339,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) lua_createtable(L, 0, count); if (!raw) { - lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key); + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); } @@ -388,6 +389,127 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) } +static int +ngx_http_lua_ngx_resp_get_headers(lua_State *L) +{ + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_request_t *r; + u_char *lowcase_key = NULL; + size_t lowcase_key_sz = 0; + ngx_uint_t i; + int n; + int max; + int raw = 0; + int count = 0; + + n = lua_gettop(L); + + if (n >= 1) { + if (lua_isnil(L, 1)) { + max = NGX_HTTP_LUA_MAX_HEADERS; + + } else { + max = luaL_checkinteger(L, 1); + } + + if (n >= 2) { + raw = lua_toboolean(L, 2); + } + + } else { + max = NGX_HTTP_LUA_MAX_HEADERS; + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + + ngx_http_lua_check_fake_request(L, r); + + part = &r->headers_out.headers.part; + count = part->nelts; + while (part->next) { + part = part->next; + count += part->nelts; + } + + if (max > 0 && count > max) { + count = max; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exceeding request header limit %d", max); + } + + lua_createtable(L, 0, count); + + if (!raw) { + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + } + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + dd("stack top: %d", lua_gettop(L)); + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + if (raw) { + lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); + + } else { + /* nginx does not even bother initializing output header entry's + * "lowcase_key" field. so we cannot count on that at all. */ + if (header[i].key.len > lowcase_key_sz) { + lowcase_key_sz = header[i].key.len * 2; + + /* we allocate via Lua's GC to prevent in-request + * leaks in the nginx request memory pools */ + lowcase_key = lua_newuserdata(L, lowcase_key_sz); + lua_insert(L, 1); + } + + ngx_strlow(lowcase_key, header[i].key.data, header[i].key.len); + lua_pushlstring(L, (char *) lowcase_key, header[i].key.len); + } + + /* stack: [udata] table key */ + + lua_pushlstring(L, (char *) header[i].value.data, + header[i].value.len); /* stack: [udata] table key + value */ + + ngx_http_lua_set_multi_value_table(L, -3); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua response header: \"%V: %V\"", + &header[i].key, &header[i].value); + + if (--count == 0) { + return 1; + } + } + + return 1; +} + + static int ngx_http_lua_ngx_header_get(lua_State *L) { @@ -730,14 +852,19 @@ ngx_http_lua_inject_resp_header_api(lua_State *L) lua_setmetatable(L, -2); lua_setfield(L, -2, "header"); + + lua_createtable(L, 0, 1); /* .resp */ + + lua_pushcfunction(L, ngx_http_lua_ngx_resp_get_headers); + lua_setfield(L, -2, "get_headers"); + + lua_setfield(L, -2, "resp"); } void -ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) +ngx_http_lua_inject_req_header_api(lua_State *L) { - int rc; - lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version); lua_setfield(L, -2, "http_version"); @@ -752,24 +879,29 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers); lua_setfield(L, -2, "get_headers"); +} - lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key); - lua_createtable(L, 0, 1); /* metatable for ngx.req.get_headers(_, true) */ - { - const char buf[] = - "local tb, key = ...\n" - "local new_key = string.gsub(string.lower(key), '_', '-')\n" - "if new_key ~= key then return tb[new_key] else return nil end"; +void +ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) +{ + int rc; + const char buf[] = + "local tb, key = ...\n" + "local new_key = string.gsub(string.lower(key), '_', '-')\n" + "if new_key ~= key then return tb[new_key] else return nil end"; - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, - "ngx.req.get_headers __index"); - } + lua_pushlightuserdata(L, &ngx_http_lua_headers_metatable_key); + + /* metatable for ngx.req.get_headers(_, true) and + * ngx.resp.get_headers(_, true) */ + lua_createtable(L, 0, 1); + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=headers metatable"); if (rc != 0) { ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to load Lua code of the metamethod for " - "ngx.req.get_headers: %i: %s", rc, lua_tostring(L, -1)); + "failed to load Lua code for the metamethod for " + "headers: %i: %s", rc, lua_tostring(L, -1)); lua_pop(L, 3); return; diff --git a/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h index 01cc7bf9e4..39f1114cdf 100644 --- a/src/ngx_http_lua_headers.h +++ b/src/ngx_http_lua_headers.h @@ -13,7 +13,8 @@ void ngx_http_lua_inject_resp_header_api(lua_State *L); -void ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L); +void ngx_http_lua_inject_req_header_api(lua_State *L); +void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 7d4f2bf00b..3de06f8e42 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -70,7 +70,7 @@ char ngx_http_lua_code_cache_key; char ngx_http_lua_regex_cache_key; char ngx_http_lua_socket_pool_key; char ngx_http_lua_coroutines_key; -char ngx_http_lua_req_get_headers_metatable_key; +char ngx_http_lua_headers_metatable_key; ngx_uint_t ngx_http_lua_location_hash = 0; @@ -782,7 +782,7 @@ static void ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) { - lua_createtable(L, 0 /* narr */, 97 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 98 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); @@ -804,6 +804,7 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, ngx_http_lua_inject_req_api(log, L); ngx_http_lua_inject_resp_header_api(L); + ngx_http_lua_create_headers_metatable(log, L); ngx_http_lua_inject_variable_api(L); ngx_http_lua_inject_shdict_api(lmcf, L); ngx_http_lua_inject_socket_tcp_api(log, L); @@ -2151,7 +2152,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */ - ngx_http_lua_inject_req_header_api(log, L); + ngx_http_lua_inject_req_header_api(L); ngx_http_lua_inject_req_uri_api(log, L); ngx_http_lua_inject_req_args_api(L); ngx_http_lua_inject_req_body_api(L); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 53dc8a0fe0..c5d9a0151d 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -54,8 +54,8 @@ extern char ngx_http_lua_coroutine_parents_key; /* coroutine anchoring table key in Lua VM registry */ extern char ngx_http_lua_coroutines_key; -/* key to the metatable for ngx.req.get_headers() */ -extern char ngx_http_lua_req_get_headers_metatable_key; +/* key to the metatable for ngx.req.get_headers() and ngx.resp.get_headers() */ +extern char ngx_http_lua_headers_metatable_key; #ifndef ngx_str_set diff --git a/t/016-resp-header.t b/t/016-resp-header.t index f597755582..9815a44012 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 10); +plan tests => repeat_each() * (blocks() * 3 + 13); #no_diff(); no_long_string(); @@ -1138,3 +1138,83 @@ foo: 32 --- no_error_log [error] + + +=== TEST 57: random access resp headers +--- config + location /resp-header { + content_by_lua ' + ngx.header["Foo"] = "bar" + ngx.header["Bar"] = "baz" + ngx.say("Foo: ", ngx.resp.get_headers()["Foo"] or "nil") + ngx.say("foo: ", ngx.resp.get_headers()["foo"] or "nil") + ngx.say("Bar: ", ngx.resp.get_headers()["Bar"] or "nil") + ngx.say("bar: ", ngx.resp.get_headers()["bar"] or "nil") + '; + } +--- request +GET /resp-header +--- response_headers +Foo: bar +Bar: baz +--- response_body +Foo: bar +foo: bar +Bar: baz +bar: baz + + + +=== TEST 58: iterating through raw resp headers +--- config + location /resp-header { + content_by_lua ' + ngx.header["Foo"] = "bar" + ngx.header["Bar"] = "baz" + local h = {} + for k, v in pairs(ngx.resp.get_headers(nil, true)) do + h[k] = v + end + ngx.say("Foo: ", h["Foo"] or "nil") + ngx.say("foo: ", h["foo"] or "nil") + ngx.say("Bar: ", h["Bar"] or "nil") + ngx.say("bar: ", h["bar"] or "nil") + '; + } +--- request +GET /resp-header +--- response_headers +Foo: bar +Bar: baz +--- response_body +Foo: bar +foo: nil +Bar: baz +bar: nil + + + +=== TEST 59: removed response headers +--- config + location /resp-header { + content_by_lua ' + ngx.header["Foo"] = "bar" + ngx.header["Foo"] = nil + ngx.header["Bar"] = "baz" + ngx.say("Foo: ", ngx.resp.get_headers()["Foo"] or "nil") + ngx.say("foo: ", ngx.resp.get_headers()["foo"] or "nil") + ngx.say("Bar: ", ngx.resp.get_headers()["Bar"] or "nil") + ngx.say("bar: ", ngx.resp.get_headers()["bar"] or "nil") + '; + } +--- request +GET /resp-header +--- response_headers +!Foo +Bar: baz +--- response_body +Foo: nil +foo: nil +Bar: baz +bar: baz + diff --git a/t/062-count.t b/t/062-count.t index b77b61df62..4ff699511f 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 97 +ngx: 98 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 97 --- request GET /test --- response_body -97 +98 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 97 +n = 98 --- no_error_log [error] @@ -301,7 +301,7 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 97 +ngx. entry count: 98 From f862915839cc4f67b5e20309bc0e6781e30cce12 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 26 Feb 2014 15:47:27 -0800 Subject: [PATCH 0475/1981] doc: documented the ngx.resp.get_headers() API function. --- README.markdown | 23 +++++++++++++++++++++++ doc/HttpLuaModule.wiki | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/README.markdown b/README.markdown index b9ea535a63..fbace3b244 100644 --- a/README.markdown +++ b/README.markdown @@ -72,6 +72,7 @@ Table of Contents * [ngx.location.capture_multi](#ngxlocationcapture_multi) * [ngx.status](#ngxstatus) * [ngx.header.HEADER](#ngxheaderheader) + * [ngx.resp.get_headers](#ngxrespget_headers) * [ngx.req.start_time](#ngxreqstart_time) * [ngx.req.http_version](#ngxreqhttp_version) * [ngx.req.raw_header](#ngxreqraw_header) @@ -2466,6 +2467,28 @@ For reading *request* headers, use the [ngx.req.get_headers](#ngxreqget_headers) [Back to TOC](#table-of-contents) +ngx.resp.get_headers +-------------------- +**syntax:** *headers = ngx.resp.get_headers(max_headers?, raw?)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua** + +Returns a Lua table holding all the current response headers for the current request. + +```lua + +local h = ngx.resp.get_headers() +for k, v in pairs(h) do + ... +end +``` + +This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers. + +This API was first introduced in the `v0.9.5` release. + +[Back to TOC](#table-of-contents) + ngx.req.start_time ------------------ **syntax:** *secs = ngx.req.start_time()* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 2b9123765f..c33ec043eb 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2018,6 +2018,24 @@ Note that ngx.header is not a normal Lua table and as such, it is n For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_headers]] function instead. +== ngx.resp.get_headers == +'''syntax:''' ''headers = ngx.resp.get_headers(max_headers?, raw?)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua*'' + +Returns a Lua table holding all the current response headers for the current request. + + +local h = ngx.resp.get_headers() +for k, v in pairs(h) do + ... +end + + +This function has the same signature as [[#ngx.req.get_headers|ngx.req.get_headers]] except getting response headers instead of request headers. + +This API was first introduced in the v0.9.5 release. + == ngx.req.start_time == '''syntax:''' ''secs = ngx.req.start_time()'' From 441d9c28bbb364e6e9aaa03ad6d6ccb47ff07438 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 28 Feb 2014 17:33:24 -0800 Subject: [PATCH 0476/1981] feature: added new API function ngx.config.ngx_configure() to return the NGINX ./configure arguments string to the Lua land. thanks Tatsuhiko Kubo for the patch in #339. --- src/ngx_http_lua_config.c | 14 +++++++++++++- t/062-count.t | 2 +- t/125-configure-args.t | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 t/125-configure-args.t diff --git a/src/ngx_http_lua_config.c b/src/ngx_http_lua_config.c index b449e3a625..022a49151f 100644 --- a/src/ngx_http_lua_config.c +++ b/src/ngx_http_lua_config.c @@ -15,6 +15,7 @@ static int ngx_http_lua_config_prefix(lua_State *L); +static int ngx_http_lua_config_configure(lua_State *L); void @@ -22,7 +23,7 @@ ngx_http_lua_inject_config_api(lua_State *L) { /* ngx.config */ - lua_createtable(L, 0, 4 /* nrec */); /* .config */ + lua_createtable(L, 0, 5 /* nrec */); /* .config */ #if (NGX_DEBUG) lua_pushboolean(L, 1); @@ -40,6 +41,9 @@ ngx_http_lua_inject_config_api(lua_State *L) lua_pushinteger(L, ngx_http_lua_version); lua_setfield(L, -2, "ngx_lua_version"); + lua_pushcfunction(L, ngx_http_lua_config_configure); + lua_setfield(L, -2, "ngx_configure"); + lua_setfield(L, -2, "config"); } @@ -51,3 +55,11 @@ ngx_http_lua_config_prefix(lua_State *L) ngx_cycle->prefix.len); return 1; } + + +static int +ngx_http_lua_config_configure(lua_State *L) +{ + lua_pushliteral(L, NGX_CONFIGURE); + return 1; +} diff --git a/t/062-count.t b/t/062-count.t index 4ff699511f..0944000b2e 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -339,7 +339,7 @@ n = 1 --- request GET /test --- response_body -n = 4 +n = 5 --- no_error_log [error] diff --git a/t/125-configure-args.t b/t/125-configure-args.t new file mode 100644 index 0000000000..6cced299eb --- /dev/null +++ b/t/125-configure-args.t @@ -0,0 +1,33 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: nginx configure +--- config + location /configure_args { + content_by_lua ' + ngx.say(ngx.config.ngx_configure()) + '; + } +--- request +GET /configure_args +--- response_body_like chop +^\s*\-\-[^-]+ +--- no_error_log +[error] + From 1916d0c2fd887b494aa32d00666cdb027cabf470 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 28 Feb 2014 17:38:24 -0800 Subject: [PATCH 0477/1981] renamed ngx.config.ngx_configure to ngx.config.nginx_configure. --- src/ngx_http_lua_config.c | 2 +- t/125-configure-args.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_config.c b/src/ngx_http_lua_config.c index 022a49151f..4283e1bd8d 100644 --- a/src/ngx_http_lua_config.c +++ b/src/ngx_http_lua_config.c @@ -42,7 +42,7 @@ ngx_http_lua_inject_config_api(lua_State *L) lua_setfield(L, -2, "ngx_lua_version"); lua_pushcfunction(L, ngx_http_lua_config_configure); - lua_setfield(L, -2, "ngx_configure"); + lua_setfield(L, -2, "nginx_configure"); lua_setfield(L, -2, "config"); } diff --git a/t/125-configure-args.t b/t/125-configure-args.t index 6cced299eb..d37a218af5 100644 --- a/t/125-configure-args.t +++ b/t/125-configure-args.t @@ -21,7 +21,7 @@ __DATA__ --- config location /configure_args { content_by_lua ' - ngx.say(ngx.config.ngx_configure()) + ngx.say(ngx.config.nginx_configure()) '; } --- request From 48af6433b6eb2f1a63a2b05e3dca14980acef586 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 28 Feb 2014 17:40:02 -0800 Subject: [PATCH 0478/1981] doc: documented the new ngx.config.nginx_configure() function. --- README.markdown | 14 ++++++++++++++ doc/HttpLuaModule.wiki | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/README.markdown b/README.markdown index fbace3b244..0f888b76a2 100644 --- a/README.markdown +++ b/README.markdown @@ -172,6 +172,7 @@ Table of Contents * [ngx.config.debug](#ngxconfigdebug) * [ngx.config.prefix](#ngxconfigprefix) * [ngx.config.nginx_version](#ngxconfignginx_version) + * [ngx.config.nginx_configure](#ngxconfignginx_configure) * [ngx.config.ngx_lua_version](#ngxconfigngx_lua_version) * [ngx.worker.exiting](#ngxworkerexiting) * [ngx.worker.pid](#ngxworkerpid) @@ -5791,6 +5792,19 @@ This API was first introduced in the `0.9.3` release. [Back to TOC](#table-of-contents) +ngx.config.nginx_configure +-------------------------- + +**syntax:** *str = ngx.config.nginx_configure()* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua** + +This function returns a string for the NGINX `./configure` command's arguments string. + +This API was first introduced in the `0.9.5` release. + +[Back to TOC](#table-of-contents) + ngx.config.ngx_lua_version -------------------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index c33ec043eb..d6e4d2e569 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4917,6 +4917,16 @@ This field take an integral value indicating the version number of the current N This API was first introduced in the 0.9.3 release. +== ngx.config.nginx_configure == + +'''syntax:''' ''str = ngx.config.nginx_configure()'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*'' + +This function returns a string for the NGINX ./configure command's arguments string. + +This API was first introduced in the 0.9.5 release. + == ngx.config.ngx_lua_version == '''syntax:''' ''ver = ngx.config.ngx_lua_version'' From d74878969c2065d76fe4009124648ed31f66d1a1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 28 Feb 2014 17:46:40 -0800 Subject: [PATCH 0479/1981] bugfix: an attempt to fix subrequests initiated by ngx.location.capture*() in the SPDY mode. --- src/ngx_http_lua_subrequest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 54f550565e..1c3f4ed4fd 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1492,6 +1492,10 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->request_body = r->request_body; +#if defined(NGX_HTTP_SPDY) && NGX_HTTP_SPDY + sr->spdy_stream = r->spdy_stream; +#endif + #ifdef HAVE_ALLOW_REQUEST_BODY_UPDATING_PATCH sr->content_length_n = -1; #endif From 9ef3ca51e74897fdd6a448b4ba6974e16e6cd872 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 28 Feb 2014 17:49:59 -0800 Subject: [PATCH 0480/1981] removed the spdy mode check from ngx.location.capture*() to renable this API again for SPDY requests. --- src/ngx_http_lua_subrequest.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 1c3f4ed4fd..efa5906008 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -165,12 +165,6 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "no request object found"); } -#if (NGX_HTTP_SPDY) - if (r->spdy_stream) { - return luaL_error(L, "spdy not supported yet"); - } -#endif - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); @@ -1492,7 +1486,7 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->request_body = r->request_body; -#if defined(NGX_HTTP_SPDY) && NGX_HTTP_SPDY +#if (NGX_HTTP_SPDY) sr->spdy_stream = r->spdy_stream; #endif From dc8e88cc2d5e0727f4c84c6c23ac241cbe974fd4 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 1 Mar 2014 18:24:01 -0800 Subject: [PATCH 0481/1981] feature: explicitly check Lua langauge version mismatch; we only accept the Lua 5.1 language (for now). --- src/ngx_http_lua_common.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index d05a24e565..327b589f43 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -26,6 +26,12 @@ #include #endif + +#if LUA_VERSION_NUM != 501 +# error unsupported Lua language version +#endif + + #ifndef MD5_DIGEST_LENGTH #define MD5_DIGEST_LENGTH 16 #endif From 911c39553924e1254735a5cbf21c47119f2da49f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 2 Mar 2014 10:17:29 -0800 Subject: [PATCH 0482/1981] increased the waiting time in two ngx.abort test cases that might fail on slow boxes. --- t/101-on-abort.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/101-on-abort.t b/t/101-on-abort.t index e6d0f23a7f..87fc194da7 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -293,7 +293,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.6 +--- wait: 0.7 --- ignore_response --- error_log client prematurely closed connection @@ -354,7 +354,7 @@ delete thread 1 --- timeout: 0.2 --- abort ---- wait: 0.2 +--- wait: 0.5 --- ignore_response --- no_error_log [error] From 880a1c85bc59889db5e722e70e194c37d39f03a7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 2 Mar 2014 10:18:01 -0800 Subject: [PATCH 0483/1981] refactor: adjusted the globals table handling a little bit. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 34 ++++++++++++------------------- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_coroutine.c | 4 ++-- src/ngx_http_lua_headerfilterby.c | 4 ++-- src/ngx_http_lua_logby.c | 4 ++-- src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_setby.c | 24 ++++++++++------------ src/ngx_http_lua_timer.c | 8 ++++---- src/ngx_http_lua_util.c | 10 ++++----- src/ngx_http_lua_util.h | 25 ++++++++++++++++++----- 11 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index e9fb9fa54e..93ebb5d6c7 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -230,7 +230,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index ee12d176c4..57d21cbb3e 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -32,9 +32,8 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, static ngx_http_output_body_filter_pt ngx_http_next_body_filter; -/* light user data key for the ngx_chain_t *in pointer in the - * Lua VM registory */ -static char ngx_http_lua_body_filter_chain_key; +/* key for the ngx_chain_t *in pointer in the Lua thread */ +#define ngx_http_lua_chain_key "__ngx_cl" /** @@ -55,9 +54,8 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, in); - lua_rawset(L, LUA_GLOBALSINDEX); + lua_setglobal(L, ngx_http_lua_chain_key); /** * we want to create empty environment for current script @@ -70,12 +68,12 @@ ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r, * all variables created in the script-env will be thrown away at the end * of the script run. * */ - ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ - lua_pushvalue(L, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ @@ -303,8 +301,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, ctx); - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_chain_key); out = lua_touserdata(L, -1); lua_pop(L, 1); @@ -362,8 +359,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L) return 1; } - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); if (idx == 2) { @@ -446,8 +442,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, /* overwriting the eof flag */ last = lua_toboolean(L, 3); - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); if (last) { @@ -503,11 +498,10 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, case LUA_TNIL: /* discard the buffers */ - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); /* key */ - lua_pushvalue(L, -1); /* key key */ - lua_rawget(L, LUA_GLOBALSINDEX); /* key val */ + lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ in = lua_touserdata(L, -1); - lua_pop(L, 1); /* key */ + lua_pop(L, 1); + lua_pushliteral(L, ngx_http_lua_chain_key); /* key */ for (cl = in; cl; cl = cl->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); @@ -534,8 +528,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, lua_typename(L, type)); } - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); lua_pop(L, 1); @@ -597,9 +590,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, } } - lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); - lua_rawset(L, LUA_GLOBALSINDEX); + lua_setglobal(L, ngx_http_lua_chain_key); return 0; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 4a3ab98aa6..ea2d80c294 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -63,7 +63,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index d9624cd93c..6f621baa24 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -104,9 +104,9 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ - lua_pushvalue(L, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(L); lua_xmove(L, co, 1); - lua_replace(co, LUA_GLOBALSINDEX); + ngx_http_lua_set_globals_table(co); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 21dfa65246..d60aab02a1 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -62,7 +62,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) * all variables created in the script-env will be thrown away at the end * of the script run. * */ - ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ initialize ngx.* namespace */ lua_pushlightuserdata(L, &ngx_http_lua_headerfilterby_ngx_key); @@ -72,7 +72,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ - lua_pushvalue(L, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 71b886fe58..875c013ab1 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -51,11 +51,11 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r) * all variables created in the script-env will be thrown away at the end * of the script run. * */ - ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1); /* the metatable for the new env */ - lua_pushvalue(L, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index d60b1fed13..f2c14a9a8d 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -226,7 +226,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index c177659eba..ed9ccc4942 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -30,9 +30,11 @@ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args); -/* chars whose addresses are used as keys in Lua VM regsitry */ -static char ngx_http_lua_setby_nargs_key; -static char ngx_http_lua_setby_args_key; +/* keys in Lua thread for fetching args and nargs in set_by_lua* */ + +#define ngx_http_lua_nargs_key "__ngx_nargs" + +#define ngx_http_lua_args_key "__ngx_args" ngx_int_t @@ -143,13 +145,11 @@ ngx_http_lua_setby_param_get(lua_State *L) idx--; /* get number of args from globals */ - lua_pushlightuserdata(L, &ngx_http_lua_setby_nargs_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_nargs_key); n = (int) lua_tointeger(L, -1); /* get args from globals */ - lua_pushlightuserdata(L, &ngx_http_lua_setby_args_key); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_args_key); v = lua_touserdata(L, -1); if (idx < 0 || idx > n - 1) { @@ -181,13 +181,11 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); - lua_pushlightuserdata(L, &ngx_http_lua_setby_nargs_key); lua_pushinteger(L, nargs); - lua_rawset(L, LUA_GLOBALSINDEX); + lua_setglobal(L, ngx_http_lua_nargs_key); - lua_pushlightuserdata(L, &ngx_http_lua_setby_args_key); lua_pushlightuserdata(L, args); - lua_rawset(L, LUA_GLOBALSINDEX); + lua_setglobal(L, ngx_http_lua_args_key); /** * we want to create empty environment for current script @@ -202,12 +200,12 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, * all variables created in the script-env will be thrown away at the end * of the script run. * */ - ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */); + ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ /* the metatable for the new env */ lua_createtable(L, 0 /* narr */, 1 /* nrec */); - lua_pushvalue(L, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable(newt, {__index = _G}) */ /* }}} */ diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 8afc1c09e7..861261f280 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -141,18 +141,18 @@ ngx_http_lua_ngx_timer_at(lua_State *L) ngx_http_lua_probe_user_coroutine_create(r, L, co); - lua_createtable(co, 0, 0); /* the new global table */ + lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ - lua_replace(co, LUA_GLOBALSINDEX); + ngx_http_lua_set_globals_table(co); /* co stack: */ @@ -172,7 +172,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) /* L stack: time func [args] thread */ /* co stack: func */ - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* co stack: func */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 3de06f8e42..8244c3c5ea 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -178,7 +178,7 @@ ngx_http_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, * | ... | * */ void -ngx_http_lua_create_new_global_table(lua_State *L, int narr, int nrec) +ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec) { lua_createtable(L, narr, nrec + 1); lua_pushvalue(L, -1); @@ -322,14 +322,14 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) * globals table. */ /* new globals table for coroutine */ - ngx_http_lua_create_new_global_table(co, 0, 0); + ngx_http_lua_create_new_globals_table(co, 0, 0); lua_createtable(co, 0, 1); - lua_pushvalue(co, LUA_GLOBALSINDEX); + ngx_http_lua_get_globals_table(co); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); - lua_replace(co, LUA_GLOBALSINDEX); + ngx_http_lua_set_globals_table(co); /* }}} */ *ref = luaL_ref(L, -2); @@ -2900,7 +2900,7 @@ ngx_http_lua_traceback(lua_State *L) return 1; /* keep it intact */ } - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + lua_getglobal(L, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index c5d9a0151d..c34a98a3b9 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -177,7 +177,7 @@ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_chain_t * ngx_http_lua_chains_get_free_buf(ngx_log_t *log, ngx_pool_t *p, ngx_chain_t **free, size_t len, ngx_buf_tag_t tag); -void ngx_http_lua_create_new_global_table(lua_State *L, int narr, int nrec); +void ngx_http_lua_create_new_globals_table(lua_State *L, int narr, int nrec); int ngx_http_lua_traceback(lua_State *L); @@ -309,13 +309,15 @@ ngx_http_lua_get_lua_vm(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } +#define ngx_http_lua_req_key "__ngx_req" + + static ngx_inline ngx_http_request_t * ngx_http_lua_get_req(lua_State *L) { ngx_http_request_t *r; - lua_pushliteral(L, "__ngx_req"); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, ngx_http_lua_req_key); r = lua_touserdata(L, -1); lua_pop(L, 1); @@ -326,9 +328,22 @@ ngx_http_lua_get_req(lua_State *L) static ngx_inline void ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r) { - lua_pushliteral(L, "__ngx_req"); lua_pushlightuserdata(L, r); - lua_rawset(L, LUA_GLOBALSINDEX); + lua_setglobal(L, ngx_http_lua_req_key); +} + + +static ngx_inline void +ngx_http_lua_get_globals_table(lua_State *L) +{ + lua_pushvalue(L, LUA_GLOBALSINDEX); +} + + +static ngx_inline void +ngx_http_lua_set_globals_table(lua_State *L) +{ + lua_replace(L, LUA_GLOBALSINDEX); } From e0c5d58f203db49bbae1629077cf73561682bd94 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 4 Mar 2014 12:16:04 -0800 Subject: [PATCH 0484/1981] doc: typo fix in a code sample for ngx.req.get_post_args(). thanks Evan for the patch in #344. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 0f888b76a2..37d8787c4f 100644 --- a/README.markdown +++ b/README.markdown @@ -2848,7 +2848,7 @@ Returns a Lua table holding all the current request POST query arguments (of the location = /test { content_by_lua ' ngx.req.read_body() - local args = ngx.req.get_post_args() + local args, err = ngx.req.get_post_args() if not args then ngx.say("failed to get post args: ", err) return diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index d6e4d2e569..8613beb0bf 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2343,7 +2343,7 @@ Returns a Lua table holding all the current request POST query arguments (of the location = /test { content_by_lua ' ngx.req.read_body() - local args = ngx.req.get_post_args() + local args, err = ngx.req.get_post_args() if not args then ngx.say("failed to get post args: ", err) return From c6e28fdc053e4db4e41f2054e822a8295b5732b8 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 4 Mar 2014 17:58:33 -0800 Subject: [PATCH 0485/1981] fixed the waiting time for a test case that could fail on slow machines. --- t/106-timer.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/106-timer.t b/t/106-timer.t index cc42653ee0..8f73a16392 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -447,7 +447,7 @@ delete thread 2 --- response_body registered timer ---- wait: 0.05 +--- wait: 0.2 --- no_error_log [error] [alert] From 1b615c46e595b467df30014a8c1f4367587f0429 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 7 Mar 2014 15:17:46 -0800 Subject: [PATCH 0486/1981] bugfix: segfault might happen in the FFI API for destroying compiled pcre regexes, which affects libraries like lua-resty-core. --- src/ngx_http_lua_regex.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 2a1b8df679..16a85aab0e 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2301,6 +2301,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) { + ngx_pool_t *old_pool; + dd("destroy regex called"); if (re == NULL || re->pool == NULL) { @@ -2308,14 +2310,18 @@ ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) } if (re->regex_sd) { + old_pool = ngx_http_lua_pcre_malloc_init(re->pool); #if LUA_HAVE_PCRE_JIT pcre_free_study(re->regex_sd); #else pcre_free(re->regex_sd); #endif + ngx_http_lua_pcre_malloc_done(old_pool); + re->regex_sd = NULL; } ngx_destroy_pool(re->pool); + re->pool = NULL; } From fb06f3958659ada56bcad0ef9a8fa4e0ce027211 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 7 Mar 2014 22:15:51 -0800 Subject: [PATCH 0487/1981] fixed a test case that could fail in the "check leak" mode due to GC delays. --- t/028-req-header.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/028-req-header.t b/t/028-req-header.t index f3c17b7530..efc270ae1a 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -319,6 +319,7 @@ Foo 3: nil --- config location /foo { content_by_lua ' + collectgarbage() local vals = ngx.req.get_headers()["Foo"] ngx.say("value is of type ", type(vals), ".") if type(vals) == "table" then From 3898993ebd3bb48e6fe826de8972e573f01afb45 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 7 Mar 2014 22:31:00 -0800 Subject: [PATCH 0488/1981] fixed a bad regressoin in commit 1b615c46. --- src/ngx_http_lua_regex.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 16a85aab0e..9210c5e9fd 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2321,7 +2321,6 @@ ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re) } ngx_destroy_pool(re->pool); - re->pool = NULL; } From cfc593bb93b85900ebec7aa9bcbdb309a24be505 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 8 Mar 2014 22:55:08 -0800 Subject: [PATCH 0489/1981] test: skipped two invalid test cases that use cosockets beyond the creating request boundary. --- t/023-rewrite/tcp-socket.t | 3 ++- t/058-tcp-socket.t | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index be51a69957..43afe82cae 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 87; +plan tests => repeat_each() * 83; our $HtmlDir = html_dir; @@ -1284,6 +1284,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) +--- SKIP --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 41b7ee5b79..4932466138 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 130; +plan tests => repeat_each() * 126; our $HtmlDir = html_dir; @@ -1259,6 +1259,7 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) +--- SKIP --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config From 97d9162338bc5f9059449bd6f73aaf27082abbe8 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 12 Mar 2014 15:49:57 -0700 Subject: [PATCH 0490/1981] updated docs for the 0.9.5 release. --- README.markdown | 12 ++++++------ doc/HttpLuaModule.wiki | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.markdown b/README.markdown index 37d8787c4f..0ad1e47cf7 100644 --- a/README.markdown +++ b/README.markdown @@ -221,7 +221,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.9.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 January 2014. +This document describes ngx_lua [v0.9.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 12 March 2014. Synopsis ======== @@ -3603,7 +3603,7 @@ ngx.exit(501) Note that while this method accepts all [HTTP status constants](#http-status-constants) as input, it only accepts `NGX_OK` and `NGX_ERROR` of the [core constants](#core-constants). -It is recommended, though not necessary (for contexts other than [header_filter_by_lua](#header_filter_by_lua), to combine the `return` statement with this call, i.e., `return ngx.exit(...)`, to give a visual hint to others reading the code. +It is recommended, though not necessary (for contexts other than [header_filter_by_lua](#header_filter_by_lua)), to combine the `return` statement with this call, i.e., `return ngx.exit(...)`, to give a visual hint to others reading the code. When being used in the context of [header_filter_by_lua](#header_filter_by_lua), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior might change in the future. So always use `return` at the same time, as suggested above. @@ -6408,7 +6408,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.5.x (last tested: 1.5.8) +* 1.5.x (last tested: 1.5.11) * 1.4.x (last tested: 1.4.4) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) @@ -6442,9 +6442,9 @@ Build the source with this module: ```bash -wget 'http://nginx.org/download/nginx-1.5.8.tar.gz' -tar -xzvf nginx-1.5.8.tar.gz -cd nginx-1.5.8/ +wget 'http://nginx.org/download/nginx-1.5.11.tar.gz' +tar -xzvf nginx-1.5.11.tar.gz +cd nginx-1.5.11/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 8613beb0bf..5bd2cda96c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.4] released on 10 January 2014. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.5] released on 12 March 2014. = Synopsis = @@ -2992,7 +2992,7 @@ Number literals can be used directly as the argument, for instance, Note that while this method accepts all [[#HTTP status constants|HTTP status constants]] as input, it only accepts NGX_OK and NGX_ERROR of the [[#core constants|core constants]]. -It is recommended, though not necessary (for contexts other than [[#header_filter_by_lua|header_filter_by_lua]], to combine the return statement with this call, i.e., return ngx.exit(...), to give a visual hint to others reading the code. +It is recommended, though not necessary (for contexts other than [[#header_filter_by_lua|header_filter_by_lua]]), to combine the return statement with this call, i.e., return ngx.exit(...), to give a visual hint to others reading the code. When being used in the context of [[#header_filter_by_lua|header_filter_by_lua]], ngx.exit() is an asynchronous operation and will return immediately. This behavior might change in the future. So always use return at the same time, as suggested above. @@ -5432,7 +5432,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.5.x (last tested: 1.5.8) +* 1.5.x (last tested: 1.5.11) * 1.4.x (last tested: 1.4.4) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) @@ -5459,9 +5459,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.5.8.tar.gz' - tar -xzvf nginx-1.5.8.tar.gz - cd nginx-1.5.8/ + wget 'http://nginx.org/download/nginx-1.5.11.tar.gz' + tar -xzvf nginx-1.5.11.tar.gz + cd nginx-1.5.11/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib From be08630ba217acd2d23c9ba305325af3505b0536 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 15 Mar 2014 22:28:54 -0700 Subject: [PATCH 0491/1981] bugfix: subrequests initiated by ngx.location.capture* with the HEAD method did not result in responses without response bodies. thanks Daniel for the report in #347. --- src/ngx_http_lua_capturefilter.c | 4 ++++ t/020-subrequest.t | 22 +++++++++++++++++++++- t/023-rewrite/subrequest.t | 1 - t/024-access/subrequest.t | 1 - 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index 8f1e20f02f..23925f8e04 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -98,6 +98,10 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) r->filter_need_in_memory = 1; r->header_sent = 1; + if (r->method == NGX_HTTP_HEAD) { + r->header_only = 1; + } + return NGX_OK; } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index b4caa300be..aaa00640a2 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -120,7 +120,6 @@ POST --- request GET /lua --- response_body -HEAD --- no_error_log [error] @@ -2740,3 +2739,24 @@ pr: Cookie: foo; bar --- no_error_log [error] + + +=== TEST 73: HEAD subrequest (github #347) +--- config + location /lua { + content_by_lua ' + res = ngx.location.capture("/index.html", + { method = ngx.HTTP_HEAD }); + ngx.say("content-length: ", res.header["Content-Length"]) + ngx.say("body: [", res.body, "]") + '; + } +--- request +GET /lua +--- response_body_like chop +^content-length: \d+ +body: \[\] +$ +--- no_error_log +[error] + diff --git a/t/023-rewrite/subrequest.t b/t/023-rewrite/subrequest.t index d30bba9fb2..15743763f1 100644 --- a/t/023-rewrite/subrequest.t +++ b/t/023-rewrite/subrequest.t @@ -116,7 +116,6 @@ POST --- request GET /lua --- response_body -HEAD diff --git a/t/024-access/subrequest.t b/t/024-access/subrequest.t index 443af1b614..8f356e34d2 100644 --- a/t/024-access/subrequest.t +++ b/t/024-access/subrequest.t @@ -116,7 +116,6 @@ POST --- request GET /lua --- response_body -HEAD From 37c86d67f84bbac6cbddcc7508f42ef21d0e7e79 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 15 Mar 2014 22:33:00 -0700 Subject: [PATCH 0492/1981] bumped version to 0.9.6. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index c61ffe2a80..83e5915902 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9005 +#define ngx_http_lua_version 9006 typedef struct { From 9b18ca311bcff8088ac38b9b1dd90c186050abb0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 16 Mar 2014 14:51:27 -0700 Subject: [PATCH 0493/1981] bugfix: the "resolver" directive's toplevel configuration in the http {} block was not respected by init_worker_by_lua. thanks Heero Zhang for the report. --- src/ngx_http_lua_initworkerby.c | 8 ++- t/124-init-worker.t | 94 ++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 7fefb2b557..21876116d6 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -32,7 +32,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_http_conf_ctx_t *conf_ctx, http_ctx; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; - ngx_http_core_loc_conf_t *clcf; + ngx_http_core_loc_conf_t *clcf, *top_clcf; lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module); @@ -46,6 +46,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) conf_ctx = ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]); http_ctx.main_conf = conf_ctx->main_conf; + top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; + ngx_memzero(&conf, sizeof(ngx_conf_t)); conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, cycle->log); @@ -145,6 +147,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) c->log->log_level = clcf->error_log->log_level; } + if (top_clcf->resolver) { + clcf->resolver = top_clcf->resolver; + } + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto failed; diff --git a/t/124-init-worker.t b/t/124-init-worker.t index 3a2f64ef59..ec3b23bd1d 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -9,9 +9,11 @@ use Test::Nginx::Socket::Lua; repeat_each(1); -plan tests => repeat_each() * (blocks() * 4 + 3); +plan tests => repeat_each() * (blocks() * 4 + 2); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + #no_diff(); no_long_string(); run_tests(); @@ -437,3 +439,93 @@ ok --- grep_error_log_out warn(): Thu, 01 Jan 1970 01:34:38 GMT + + +=== TEST 13: cosocket with resolver +--- timeout: 10 +--- http_config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + resolver_timeout 1s; + init_worker_by_lua ' + -- global + logs = "" + done = false + local function say(...) + logs = logs .. table.concat({...}) .. "\\n" + end + + local function handler() + local sock = ngx.socket.tcp() + local port = 80 + local ok, err = sock:connect("agentzh.org", port) + if not ok then + say("failed to connect: ", err) + done = true + return + end + + say("connected: ", ok) + + local req = "GET / HTTP/1.0\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + say("failed to send request: ", err) + done = true + return + end + + say("request sent: ", bytes) + + local line, err = sock:receive() + if line then + say("first line received: ", line) + + else + say("failed to receive the first line: ", err) + end + + line, err = sock:receive() + if line then + say("second line received: ", line) + + else + say("failed to receive the second line: ", err) + end + + done = true + end + + local ok, err = ngx.timer.at(0, handler) + if not ok then + say("failed to create timer: ", err) + else + say("timer created") + end + '; + +--- config + location = /t { + content_by_lua ' + local i = 0 + while not done and i < 1000 do + ngx.sleep(0.001) + i = i + 1 + end + ngx.print(logs) + '; + } +--- request +GET /t +--- response_body +timer created +connected: 1 +request sent: 56 +first line received: HTTP/1.1 200 OK +second line received: Server: ngx_openresty +--- no_error_log +[error] +--- timeout: 10 + From 6c56337d7ae07b3c51d209ffb8da3f19a7e37c9f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 16 Mar 2014 15:17:00 -0700 Subject: [PATCH 0494/1981] bugfix: init_worker_by_lua should honor the lua_socket_log_errors directive's configuration in the http {} block. --- src/ngx_http_lua_initworkerby.c | 7 +- t/124-init-worker.t | 154 +++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 21876116d6..e801560990 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -30,7 +30,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_conf_ctx_t *conf_ctx, http_ctx; - ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_loc_conf_t *llcf, *top_llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf, *top_clcf; @@ -47,6 +47,7 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) http_ctx.main_conf = conf_ctx->main_conf; top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; + top_llcf = conf_ctx->loc_conf[ngx_http_lua_module.ctx_index]; ngx_memzero(&conf, sizeof(ngx_conf_t)); @@ -161,7 +162,9 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) r->read_event_handler = ngx_http_block_reading; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - llcf->log_socket_errors = 0; + if (top_llcf->log_socket_errors != NGX_CONF_UNSET) { + llcf->log_socket_errors = top_llcf->log_socket_errors; + } ngx_http_lua_set_req(lmcf->lua, r); diff --git a/t/124-init-worker.t b/t/124-init-worker.t index ec3b23bd1d..8b6545a3ad 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(1); -plan tests => repeat_each() * (blocks() * 4 + 2); +plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; @@ -529,3 +529,155 @@ second line received: Server: ngx_openresty [error] --- timeout: 10 + + +=== TEST 14: connection refused (tcp) - log_errors on by default +--- http_config + init_worker_by_lua ' + logs = "" + done = false + local function say(...) + logs = logs .. table.concat{...} .. "\\n" + end + + local function handler() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 16787) + if not ok then + say("failed to connect: ", err) + else + say("connect: ", ok, " ", err) + end + end + + local ok, err = ngx.timer.at(0, handler) + if not ok then + say("failed to create timer: ", err) + else + say("timer created") + end + '; + +--- config + location = /t { + content_by_lua ' + local i = 0 + while not done and i < 1000 do + ngx.sleep(0.001) + i = i + 1 + end + ngx.print(logs) + '; + } + +--- request + GET /t +--- response_body +timer created +failed to connect: connection refused +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ + + + +=== TEST 15: connection refused (tcp) - log_errors explicitly on +--- http_config + lua_socket_log_errors on; + init_worker_by_lua ' + logs = "" + done = false + local function say(...) + logs = logs .. table.concat{...} .. "\\n" + end + + local function handler() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 16787) + if not ok then + say("failed to connect: ", err) + else + say("connect: ", ok, " ", err) + end + end + + local ok, err = ngx.timer.at(0, handler) + if not ok then + say("failed to create timer: ", err) + else + say("timer created") + end + '; + +--- config + location = /t { + content_by_lua ' + local i = 0 + while not done and i < 1000 do + ngx.sleep(0.001) + i = i + 1 + end + ngx.print(logs) + '; + } + +--- request + GET /t +--- response_body +timer created +failed to connect: connection refused +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ + + + +=== TEST 16: connection refused (tcp) - log_errors explicitly off +--- http_config + lua_socket_log_errors off; + init_worker_by_lua ' + logs = "" + done = false + local function say(...) + logs = logs .. table.concat{...} .. "\\n" + end + + local function handler() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", 16787) + if not ok then + say("failed to connect: ", err) + else + say("connect: ", ok, " ", err) + end + end + + local ok, err = ngx.timer.at(0, handler) + if not ok then + say("failed to create timer: ", err) + else + say("timer created") + end + '; + +--- config + location = /t { + content_by_lua ' + local i = 0 + while not done and i < 1000 do + ngx.sleep(0.001) + i = i + 1 + end + ngx.print(logs) + '; + } + +--- request + GET /t +--- response_body +timer created +failed to connect: connection refused +--- no_error_log eval +[ +'qr/connect\(\) failed \(\d+: Connection refused\)/', +'[error]', +] + From a4db3e1b2d812c98d5cbb6093808e714c2dd1137 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 17 Mar 2014 14:41:31 -0700 Subject: [PATCH 0495/1981] bugfix: we should prefix our chunk names for from-string lua source (which also leads to nicer error messages). thanks Mike Pall for the catch. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_coroutine.c | 2 +- src/ngx_http_lua_directive.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- src/ngx_http_lua_initby.c | 2 +- src/ngx_http_lua_initworkerby.c | 2 +- src/ngx_http_lua_logby.c | 2 +- src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_socket_tcp.c | 2 +- t/001-set.t | 2 +- t/009-log.t | 38 ++++++++-------- t/023-rewrite/on-abort.t | 2 +- t/023-rewrite/uthread-spawn.t | 2 +- t/024-access/on-abort.t | 2 +- t/024-access/uthread-spawn.t | 2 +- t/041-header-filter.t | 2 +- t/044-req-body.t | 6 +-- t/064-pcall.t | 4 +- t/073-backtrace.t | 2 +- t/075-logby.t | 2 +- t/082-body-filter.t | 2 +- t/091-coroutine.t | 4 +- t/093-uthread-spawn.t | 2 +- t/098-uthread-wait.t | 12 +++--- t/101-on-abort.t | 2 +- t/106-timer.t | 16 +++---- t/107-timer-errors.t | 72 +++++++++++++++---------------- t/108-timer-safe.t | 8 ++-- 30 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 93ebb5d6c7..c61ed485b6 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -155,7 +155,7 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->access_src.value.data, llcf->access_src.value.len, llcf->access_src_key, - "access_by_lua"); + "=access_by_lua"); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 57d21cbb3e..60c2267ea5 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -163,7 +163,7 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) rc = ngx_http_lua_cache_loadbuffer(L, llcf->body_filter_src.value.data, llcf->body_filter_src.value.len, llcf->body_filter_src_key, - "body_filter_by_lua"); + "=body_filter_by_lua"); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index ea2d80c294..15aeef0ab6 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -275,7 +275,7 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->content_src.value.data, llcf->content_src.value.len, llcf->content_src_key, - "content_by_lua"); + "=content_by_lua"); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 6f621baa24..91d08a0739 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -300,7 +300,7 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) #endif ; - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "coroutine.wrap"); + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=coroutine.wrap"); } if (rc != 0) { diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 791207af24..b4af52f1c5 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -298,7 +298,7 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(L, filter_data->script.data, filter_data->script.len, - filter_data->key, "set_by_lua"); + filter_data->key, "=set_by_lua"); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index d60aab02a1..9aa22dc019 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -179,7 +179,7 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->header_filter_src.value.data, llcf->header_filter_src.value.len, llcf->header_filter_src_key, - "header_filter_by_lua"); + "=header_filter_by_lua"); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index 4293f93306..e8941da6ca 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -20,7 +20,7 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, int status; status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, - lmcf->init_src.len, "init_by_lua") + lmcf->init_src.len, "=init_by_lua") || ngx_http_lua_do_call(log, L); return ngx_http_lua_report(log, L, status, "init_by_lua"); diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index e801560990..4240201df4 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -199,7 +199,7 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, int status; status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, - lmcf->init_worker_src.len, "init_worker_by_lua") + lmcf->init_worker_src.len, "=init_worker_by_lua") || ngx_http_lua_do_call(log, L); return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 875c013ab1..37fabb85e3 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -127,7 +127,7 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ rc = ngx_http_lua_cache_loadbuffer(L, llcf->log_src.value.data, llcf->log_src.value.len, - llcf->log_src_key, "log_by_lua"); + llcf->log_src_key, "=log_by_lua"); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index f2c14a9a8d..057ea416fa 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -157,7 +157,7 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) rc = ngx_http_lua_cache_loadbuffer(L, llcf->rewrite_src.value.data, llcf->rewrite_src.value.len, llcf->rewrite_src_key, - "rewrite_by_lua"); + "=rewrite_by_lua"); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 097904c370..c89630e8a9 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -132,7 +132,7 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) " local ok, err = sock:connect(...)" " if ok then return sock else return nil, err end"; - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "ngx.socket.connect"); + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=ngx.socket.connect"); } if (rc != NGX_OK) { diff --git a/t/001-set.t b/t/001-set.t index 90f5c6f32a..defa33c9ff 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -574,7 +574,7 @@ GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -failed to run set_by_lua*: [string "set_by_lua"]:1: Bad +failed to run set_by_lua*: set_by_lua:1: Bad diff --git a/t/009-log.t b/t/009-log.t index 47c1fcf754..c2b9088061 100644 --- a/t/009-log.t +++ b/t/009-log.t @@ -31,7 +31,7 @@ GET /log before log after log --- error_log eval -qr/\[\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -50,7 +50,7 @@ GET /log before log after log --- error_log eval -qr/\[emerg\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[emerg\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -69,7 +69,7 @@ GET /log before log after log --- error_log eval -qr/\[alert\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[alert\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -88,7 +88,7 @@ GET /log before log after log --- error_log eval -qr/\[crit\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[crit\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -107,7 +107,7 @@ GET /log before log after log --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -126,7 +126,7 @@ GET /log before log after log --- error_log eval -qr/\[warn\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[warn\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -145,7 +145,7 @@ GET /log before log after log --- error_log eval -qr/\[notice\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[notice\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -164,7 +164,7 @@ GET /log before log after log --- error_log eval -qr/\[info\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[info\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -183,7 +183,7 @@ GET /log before log after log --- error_log eval -qr/\[debug\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[debug\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -202,7 +202,7 @@ GET /log before log after log --- error_log eval -qr/\[notice\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:3: hello, log12343.14159/ +qr/\[notice\] \S+: \S+ \[lua\] content_by_lua:3: hello, log12343.14159/ @@ -222,9 +222,9 @@ GET /log hi --- error_log eval [ -'[lua] [string "content_by_lua"]:2: ,', -'[lua] [string "content_by_lua"]:3: nil,', -'[lua] [string "content_by_lua"]:4: nil: nil,', +'[lua] content_by_lua:2: ,', +'[lua] content_by_lua:3: nil,', +'[lua] content_by_lua:4: nil: nil,', ] @@ -243,7 +243,7 @@ GET /log --- response_body 32 --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] \[string "set_by_lua"\]:2: HELLO,/ +qr/\[error\] \S+: \S+ \[lua\] set_by_lua:2: HELLO,/ @@ -261,7 +261,7 @@ GET /log --- response_body 32 --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] \[string "set_by_lua"\]:2: truefalsenil,/ +qr/\[error\] \S+: \S+ \[lua\] set_by_lua:2: truefalsenil,/ @@ -279,7 +279,7 @@ GET /log --- response_headers foo: 32 --- error_log eval -qr/\[notice\] .*? \[lua\] \[string "header_filter_by_lua"\]:2: hello world/ +qr/\[notice\] .*? \[lua\] header_filter_by_lua:2: hello world/ --- response_body hi @@ -301,7 +301,7 @@ foo: 32 --- response_body hi --- error_log eval -qr/\[error\] .*? \[lua\] \[string "header_filter_by_lua"\]:2: howdy, lua!/ +qr/\[error\] .*? \[lua\] header_filter_by_lua:2: howdy, lua!/ @@ -342,7 +342,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:7: bar\(\): hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua:7: bar\(\): hello, log12343.14159/ @@ -372,7 +372,7 @@ GET /log --- response_body done --- error_log eval -qr/\[error\] \S+: \S+ \[lua\] \[string "content_by_lua"\]:8:(?: foo\(\):)? hello, log12343.14159/ +qr/\[error\] \S+: \S+ \[lua\] content_by_lua:8:(?: foo\(\):)? hello, log12343.14159/ diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index de25424c73..a799038812 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -309,7 +309,7 @@ lua req cleanup --- error_log client prematurely closed connection on abort called -lua user thread aborted: runtime error: [string "rewrite_by_lua"]:4: attempt to abort with pending subrequests +lua user thread aborted: runtime error: rewrite_by_lua:4: attempt to abort with pending subrequests main handler done diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index 22f16cafe4..c1b8c26c59 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -249,7 +249,7 @@ delete thread 3 --- response_body after --- error_log -lua user thread aborted: runtime error: [string "rewrite_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: rewrite_by_lua:3: attempt to call field 'blah' (a nil value) diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index e62a7f577a..8fff56f3c9 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -308,7 +308,7 @@ lua req cleanup --- error_log client prematurely closed connection on abort called -lua user thread aborted: runtime error: [string "access_by_lua"]:4: attempt to abort with pending subrequests +lua user thread aborted: runtime error: access_by_lua:4: attempt to abort with pending subrequests main handler done diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index 63f6115b6e..49139f3032 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -249,7 +249,7 @@ delete thread 3 --- response_body after --- error_log -lua user thread aborted: runtime error: [string "access_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: access_by_lua:3: attempt to call field 'blah' (a nil value) diff --git a/t/041-header-filter.t b/t/041-header-filter.t index c97a6292bc..3254a3e23d 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -455,7 +455,7 @@ GET /lua GET /lua --- ignore_response --- error_log -failed to run header_filter_by_lua*: [string "header_filter_by_lua"]:2: Something bad +failed to run header_filter_by_lua*: header_filter_by_lua:2: Something bad --- no_error_log [alert] diff --git a/t/044-req-body.t b/t/044-req-body.t index a856cee120..18c53aa0cf 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -316,7 +316,7 @@ yeah --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -lua entry thread aborted: runtime error: [string "content_by_lua"]:2: request body not read yet +lua entry thread aborted: runtime error: content_by_lua:2: request body not read yet --- no_error_log [alert] @@ -574,7 +574,7 @@ Will you change this world? --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -lua entry thread aborted: runtime error: [string "rewrite_by_lua"]:3: request body not read yet +lua entry thread aborted: runtime error: rewrite_by_lua:3: request body not read yet --- no_error_log [alert] @@ -977,7 +977,7 @@ a client request body is buffered to a temporary file --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -lua entry thread aborted: runtime error: [string "content_by_lua"]:2: request body not read yet +lua entry thread aborted: runtime error: content_by_lua:2: request body not read yet --- no_error_log [alert] diff --git a/t/064-pcall.t b/t/064-pcall.t index 595cd76229..3f9c419ff9 100644 --- a/t/064-pcall.t +++ b/t/064-pcall.t @@ -48,7 +48,7 @@ __DATA__ GET /test --- response_body res len: 2 -res: false[string "content_by_lua"]:4: zero error +res: falsecontent_by_lua:4: zero error res len: 4 res: true23hellotrue --- no_error_log @@ -95,7 +95,7 @@ res: true23hellotrue --- request GET /test --- response_body -error handler called: [string "content_by_lua"]:4: zero error +error handler called: content_by_lua:4: zero error res len: 2 res: falsethis is the new err res len: 4 diff --git a/t/073-backtrace.t b/t/073-backtrace.t index 1b04c2448e..a852e4bcde 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -64,7 +64,7 @@ stack traceback: in function 'error' : in function 'bar' :5: in function 'foo' -:7: in function <[string "content_by_lua"]:1> +:7: in function diff --git a/t/075-logby.t b/t/075-logby.t index ba8330ad25..2b4fa460e1 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -202,7 +202,7 @@ GET /lua --- response_body ok --- error_log -failed to run log_by_lua*: [string "log_by_lua"]:1: Bad +failed to run log_by_lua*: log_by_lua:1: Bad diff --git a/t/082-body-filter.t b/t/082-body-filter.t index e488b25b68..0d93107c9d 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -318,7 +318,7 @@ hiya globe GET /t --- ignore_response --- error_log -failed to run body_filter_by_lua*: [string "body_filter_by_lua"]:4: something bad happened! +failed to run body_filter_by_lua*: body_filter_by_lua:4: something bad happened! diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 6db54cfd1b..bf86567baf 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -898,11 +898,11 @@ chunk: true --- request GET /t --- response_body -child: resume: false[string "content_by_lua"]:4: bad +child: resume: falsecontent_by_lua:4: bad child: status: dead parent: status: running --- error_log -lua coroutine: runtime error: [string "content_by_lua"]:4: bad +lua coroutine: runtime error: content_by_lua:4: bad diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 713c351dab..4e1a2e3fdb 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -224,7 +224,7 @@ delete thread 1 --- response_body after --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: content_by_lua:3: attempt to call field 'blah' (a nil value) diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index fe13845e5a..1d70067a0e 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -420,7 +420,7 @@ hello in thread thread created: zombie failed to wait thread: bad bad! --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:4: bad bad! +lua user thread aborted: runtime error: content_by_lua:4: bad bad! @@ -470,7 +470,7 @@ thread created: running hello in thread failed to wait thread: bad bad! --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:5: bad bad! +lua user thread aborted: runtime error: content_by_lua:5: bad bad! @@ -886,7 +886,7 @@ f status: dead g status: zombie --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:7: f done +lua user thread aborted: runtime error: content_by_lua:7: f done @@ -962,7 +962,7 @@ g status: running g: hello --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:8: f done +lua user thread aborted: runtime error: content_by_lua:8: f done @@ -1185,7 +1185,7 @@ delete thread 1 --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -lua entry thread aborted: runtime error: [string "content_by_lua"]:11: attempt to wait on a coroutine that is not a user thread +lua entry thread aborted: runtime error: content_by_lua:11: attempt to wait on a coroutine that is not a user thread @@ -1221,7 +1221,7 @@ delete thread 2 ok --- error_log -lua user thread aborted: runtime error: [string "content_by_lua"]:5: f done +lua user thread aborted: runtime error: content_by_lua:5: f done diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 87fc194da7..9e80ddb5e1 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -298,7 +298,7 @@ lua req cleanup --- error_log client prematurely closed connection on abort called -lua user thread aborted: runtime error: [string "content_by_lua"]:4: attempt to abort with pending subrequests +lua user thread aborted: runtime error: content_by_lua:4: attempt to abort with pending subrequests main handler done diff --git a/t/106-timer.t b/t/106-timer.t index 8f73a16392..106a3abcf7 100644 --- a/t/106-timer.t +++ b/t/106-timer.t @@ -69,7 +69,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", @@ -115,7 +115,7 @@ foo = nil --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -161,7 +161,7 @@ foo = 3 --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -209,7 +209,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -455,7 +455,7 @@ registered timer --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0(?:[^.]|\.00)/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0(?:[^.]|\.00)/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -588,7 +588,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] \[string "log_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -2112,7 +2112,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", @@ -2155,7 +2155,7 @@ timer prematurely expired: true --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: .*?, context: ngx\.timer/, +qr/\[lua\] content_by_lua:\d+: elapsed: .*?, context: ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection", "timer prematurely expired: false", diff --git a/t/107-timer-errors.t b/t/107-timer-errors.t index d13c6d875e..12e6564863 100644 --- a/t/107-timer-errors.t +++ b/t/107-timer-errors.t @@ -49,7 +49,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -88,7 +88,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -127,7 +127,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -166,7 +166,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -205,7 +205,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -244,7 +244,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -283,7 +283,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -322,7 +322,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -361,7 +361,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -400,7 +400,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -439,7 +439,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -478,7 +478,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -517,7 +517,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -556,7 +556,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -595,7 +595,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -634,7 +634,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -673,7 +673,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -712,7 +712,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -751,7 +751,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -790,7 +790,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -829,7 +829,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -868,7 +868,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -907,7 +907,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -946,7 +946,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -985,7 +985,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1024,7 +1024,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1063,7 +1063,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1102,7 +1102,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1141,7 +1141,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1180,7 +1180,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1219,7 +1219,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1258,7 +1258,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1297,7 +1297,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1336,7 +1336,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the current context/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the current context/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1375,7 +1375,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -1417,7 +1417,7 @@ registered timer --- error_log eval [ -qr/\[error\] .*? runtime error: \[string "content_by_lua"\]:3: API disabled in the context of ngx\.timer/, +qr/\[error\] .*? runtime error: content_by_lua:3: API disabled in the context of ngx\.timer/, "lua ngx.timer expired", "http lua close fake http connection" ] diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t index c9e90d43b1..dd77f4043d 100644 --- a/t/108-timer-safe.t +++ b/t/108-timer-safe.t @@ -68,7 +68,7 @@ registered timer --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -117,7 +117,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -365,7 +365,7 @@ registered timer --- error_log eval [ -qr/\[lua\] \[string "content_by_lua"\]:\d+: elapsed: 0(?:[^.]|\.00)/, +qr/\[lua\] content_by_lua:\d+: elapsed: 0(?:[^.]|\.00)/, "lua ngx.timer expired", "http lua close fake http connection" ] @@ -500,7 +500,7 @@ hello world [ "registered timer", qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] \[string "log_by_lua"\]:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] log_by_lua:\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, "lua ngx.timer expired", "http lua close fake http connection" ] From 382c72010b64b7b36fd0ddde62fb7624305b8376 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 17 Mar 2014 14:53:59 -0700 Subject: [PATCH 0496/1981] change: it is now the user's responsibility to clear the captures table for ngx.re.match(). --- src/ngx_http_lua_regex.c | 2 ++ t/034-match.t | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 9210c5e9fd..06e2d219ac 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -214,6 +214,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) luaL_checktype(L, 5, LUA_TTABLE); res_tb_idx = 5; +#if 0 /* clear the Lua table */ lua_pushnil(L); while (lua_next(L, res_tb_idx) != 0) { @@ -222,6 +223,7 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) lua_pushnil(L); lua_rawset(L, res_tb_idx); } +#endif } else { group_id = luaL_checkint(L, 5); diff --git a/t/034-match.t b/t/034-match.t index bc5a35bbf0..ba4bcc572c 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -1122,6 +1122,6 @@ failed to match --- response_body 1: m size: 2 1: res size: 2 -2: m size: 1 -2: res size: 1 +2: m size: 2 +2: res size: 2 From 414db1a80b489cca4fbab96fddc018ccd61dab78 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 18 Mar 2014 14:23:36 -0700 Subject: [PATCH 0497/1981] bugfix: accessing a cosocket object from a request which does not create it could lead to segmentation faults. now we throw out a Lua error "bad request" properly in this case. thanks Ross Timson for the report. --- src/ngx_http_lua_socket_tcp.c | 41 +++- t/023-rewrite/tcp-socket.t | 351 +++++++++++++++++++++++++++++++++- t/058-tcp-socket.t | 339 +++++++++++++++++++++++++++++++- 3 files changed, 720 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index c89630e8a9..53064ce163 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -400,6 +400,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) lua_pop(L, 1); if (u) { + if (u->request && u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); @@ -1131,6 +1135,10 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); @@ -1757,6 +1765,10 @@ ngx_http_lua_socket_tcp_send(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); @@ -2008,6 +2020,10 @@ ngx_http_lua_socket_tcp_close(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); @@ -2730,14 +2746,21 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) return 2; } + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } - r = u->request; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket receiveuntil iterator"); @@ -3533,17 +3556,21 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - b = &u->buffer; if (b->start && ngx_buf_size(b)) { diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 43afe82cae..cacbaa8f46 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 83; +plan tests => repeat_each() * 111; our $HtmlDir = html_dir; @@ -1284,7 +1284,6 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) ---- SKIP --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config @@ -2037,3 +2036,351 @@ close: 1 nil --- no_error_log [error] + + +=== TEST 33: bad request tries to connect +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" +--- config + server_tokens off; + location = /main { + echo_location /t?reset=1; + echo_location /t; + } + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + rewrite_by_lua ' + local test = require "test" + if ngx.var.arg_reset then + test.new_sock() + end + local sock = test.get_sock() + local ok, err = sock:connect("127.0.0.1", ngx.var.port) + if not ok then + ngx.say("failed to connect: ", err) + else + ngx.say("connected") + end + '; + + content_by_lua return; + } +--- user_files +>>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected + repeat_each() * 126; +plan tests => repeat_each() * 154; our $HtmlDir = html_dir; @@ -1259,7 +1259,6 @@ received: OK|failed to close: closed)$/ === TEST 22: cannot survive across request boundary (connect) ---- SKIP --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config @@ -2667,3 +2666,339 @@ close: nil closed --- error_log lua clean up the timer for pending ngx.sleep + + +=== TEST 44: bad request tries to connect +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" +--- config + server_tokens off; + location = /main { + echo_location /t?reset=1; + echo_location /t; + } + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local test = require "test" + if ngx.var.arg_reset then + test.new_sock() + end + local sock = test.get_sock() + local ok, err = sock:connect("127.0.0.1", ngx.var.port) + if not ok then + ngx.say("failed to connect: ", err) + else + ngx.say("connected") + end + '; + } +--- user_files +>>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.tcp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^connected + Date: Tue, 18 Mar 2014 14:50:57 -0700 Subject: [PATCH 0498/1981] bugfix: accessing a datagram cosocket object from a request which does not create it could lead to segmentation faults. now we throw out a Lua error "bad request" properly in this case. --- src/ngx_http_lua_socket_udp.c | 16 ++ t/087-udp-socket.t | 286 +++++++++++++++++++++++++++++++++- 2 files changed, 299 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index d6c29796ea..15a091d231 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -225,6 +225,10 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) lua_pop(L, 1); if (u) { + if (u->request && u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); @@ -811,6 +815,10 @@ ngx_http_lua_socket_udp_send(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->ft_type) { u->ft_type = 0; } @@ -938,6 +946,10 @@ ngx_http_lua_socket_udp_receive(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->ft_type) { u->ft_type = 0; } @@ -1479,6 +1491,10 @@ ngx_http_lua_socket_udp_close(lua_State *L) return 2; } + if (u->request != r) { + return luaL_error(L, "bad request"); + } + if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 5f03f38be0..f9d475be7f 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (3 * blocks() + 8); +plan tests => repeat_each() * (3 * blocks() + 13); our $HtmlDir = html_dir; @@ -263,7 +263,7 @@ M(http-lua-info) { GET /main --- response_body_like: \b500\b --- error_log -failed to connect: socket busy +content_by_lua:8: bad request @@ -328,7 +328,7 @@ end GET /main --- response_body_like: \b500\b --- error_log -failed to receive data: socket busy +content_by_lua:6: bad request @@ -806,3 +806,283 @@ probe syscall.socket.return, syscall.connect.return { [crit] --- skip_eval: 3: $^O ne 'linux' + + +=== TEST 15: bad request tries to setpeer +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" +--- config + server_tokens off; + location = /main { + echo_location /t?reset=1; + echo_location /t; + } + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local test = require "test" + if ngx.var.arg_reset then + local sock = test.new_sock() + local ok, err = sock:setpeername("127.0.0.1", ngx.var.port) + if not ok then + ngx.say("failed to set peer: ", err) + else + ngx.say("peer set") + end + return + end + local sock = test.get_sock() + sock:setpeername("127.0.0.1", ngx.var.port) + '; + } +--- user_files +>>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.udp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^peer set +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.udp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^peer set +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.udp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^peer set +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.udp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^peer set +>> test.lua +module("test", package.seeall) + +local sock + +function new_sock() + sock = ngx.socket.udp() + return sock +end + +function get_sock() + return sock +end +--- request +GET /main +--- response_body_like eval +qr/^peer set + Date: Wed, 19 Mar 2014 17:28:28 -0700 Subject: [PATCH 0499/1981] skipped 2 test cases that are nonderterministic. --- t/023-rewrite/tcp-socket.t | 3 ++- t/058-tcp-socket.t | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index cacbaa8f46..ca5bf22081 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 111; +plan tests => repeat_each() * 107; our $HtmlDir = html_dir; @@ -1357,6 +1357,7 @@ received: OK lua reuse socket upstream ctx --- no_error_log [error] +--- SKIP diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 41c08e0994..5ffcd81ff6 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 154; +plan tests => repeat_each() * 150; our $HtmlDir = html_dir; @@ -1330,6 +1330,7 @@ received: OK lua reuse socket upstream ctx --- no_error_log [error] +--- SKIP From e5eefed3282724076e1153d153cdab546fcb6675 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 20 Mar 2014 12:51:40 -0700 Subject: [PATCH 0500/1981] updated docs to reflect the change in commit 382c7201. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 0ad1e47cf7..8d9bf22111 100644 --- a/README.markdown +++ b/README.markdown @@ -4206,7 +4206,7 @@ To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the pcre JIT compiling result: 1 -Starting from the `0.9.4` release, this function also accepts a 5th argument, `res_table`, for letting the caller supply the Lua table used to hold all the capturing results. This table will always be cleared before inserting the resulting capturing data. This is very useful for recycling Lua tables and saving GC and table allocation overhead. +Starting from the `0.9.4` release, this function also accepts a 5th argument, `res_table`, for letting the caller supply the Lua table used to hold all the capturing results. Starting from `0.9.6`, it is the caller's responsibility to ensure this table is empty. This is very useful for recycling Lua tables and saving GC and table allocation overhead. This feature was introduced in the `v0.2.1rc11` release. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5bd2cda96c..b0c3a0f8dd 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3497,7 +3497,7 @@ To confirm that PCRE JIT is enabled, activate the Nginx debug log by adding the pcre JIT compiling result: 1 -Starting from the 0.9.4 release, this function also accepts a 5th argument, res_table, for letting the caller supply the Lua table used to hold all the capturing results. This table will always be cleared before inserting the resulting capturing data. This is very useful for recycling Lua tables and saving GC and table allocation overhead. +Starting from the 0.9.4 release, this function also accepts a 5th argument, res_table, for letting the caller supply the Lua table used to hold all the capturing results. Starting from 0.9.6, it is the caller's responsibility to ensure this table is empty. This is very useful for recycling Lua tables and saving GC and table allocation overhead. This feature was introduced in the v0.2.1rc11 release. From bec802ea9c41746092addb13ab6c42a466a34246 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 20 Mar 2014 13:18:51 -0700 Subject: [PATCH 0501/1981] bumped version to 0.9.6. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 8d9bf22111..8fccf94696 100644 --- a/README.markdown +++ b/README.markdown @@ -221,7 +221,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.9.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 12 March 2014. +This document describes ngx_lua [v0.9.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 March 2014. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b0c3a0f8dd..3669cce29a 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.5] released on 12 March 2014. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.6] released on 20 March 2014. = Synopsis = From 5d4afab7aee3ee0cb3d8b8c875762d0c2d49f379 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 22 Mar 2014 11:09:13 -0700 Subject: [PATCH 0502/1981] optimize: we no longer clear "ctx->user_co_ctx" in ngx_http_lua_reset_ctx. --- src/ngx_http_lua_util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 8244c3c5ea..0a5823bd42 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -903,10 +903,12 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_http_lua_del_all_threads(r, L, ctx); +#if 0 if (ctx->user_co_ctx) { /* no way to destroy a list but clean up the whole pool */ ctx->user_co_ctx = NULL; } +#endif ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t)); From bbb7e05d91c4682dbf1583b401ae62bb67cae539 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 22 Mar 2014 11:10:41 -0700 Subject: [PATCH 0503/1981] added stronger assertions to the stream-typed cosocket implementation. --- src/ngx_http_lua_socket_tcp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 53064ce163..47efd2c1ba 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -12,6 +12,7 @@ #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_uthread.h" #include "ngx_http_lua_output.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_probe.h" @@ -2310,7 +2311,6 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - ngx_http_lua_assert(u->co_ctx != NULL); coctx = u->co_ctx; coctx->cleanup = NULL; u->co_ctx = NULL; @@ -2323,6 +2323,9 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, ctx->resume_handler = ngx_http_lua_socket_tcp_resume; ctx->cur_co_ctx = coctx; + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2353,19 +2356,18 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - ngx_http_lua_assert(u->co_ctx != NULL); coctx = u->co_ctx; coctx->cleanup = NULL; u->co_ctx = NULL; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return; - } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; ctx->cur_co_ctx = coctx; + ngx_http_lua_assert(coctx && (!ngx_http_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); From f07a55b289e6704b3f929e5b4e50f98f910fe720 Mon Sep 17 00:00:00 2001 From: cubicdaiya Date: Thu, 27 Mar 2014 10:33:20 +0900 Subject: [PATCH 0504/1981] use lua_pushliteral instead of lua_pushlstring --- src/ngx_http_lua_phase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index e0aa4500f0..880ee7612c 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -30,7 +30,7 @@ ngx_http_lua_ngx_get_phase(lua_State *L) * phase. */ if (r == NULL) { - lua_pushlstring(L, (char *) "init", sizeof("init") - 1); + lua_pushliteral(L, "init"); return 1; } From 8542d4365aa1f5e8d8448457bd7ee0aee4c6f706 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 30 Mar 2014 15:00:20 -0700 Subject: [PATCH 0505/1981] refactor: improved the error handling and logging in the Lua code loader and closure factory. --- src/ngx_http_lua_accessby.c | 4 +- src/ngx_http_lua_bodyfilterby.c | 4 +- src/ngx_http_lua_cache.c | 63 +++++++++++++++++++++++-------- src/ngx_http_lua_cache.h | 9 +++-- src/ngx_http_lua_clfactory.c | 12 +++--- src/ngx_http_lua_clfactory.h | 4 +- src/ngx_http_lua_contentby.c | 5 ++- src/ngx_http_lua_directive.c | 4 +- src/ngx_http_lua_headerfilterby.c | 5 ++- src/ngx_http_lua_logby.c | 4 +- src/ngx_http_lua_rewriteby.c | 4 +- t/001-set.t | 2 +- t/002-content.t | 2 +- t/023-rewrite/sanity.t | 2 +- t/024-access/sanity.t | 2 +- t/041-header-filter.t | 2 +- t/075-logby.t | 2 +- t/081-bytecode.t | 4 +- t/082-body-filter.t | 2 +- 19 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index c61ed485b6..ca79ea3457 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -152,7 +152,7 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->access_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->access_src.value.data, llcf->access_src.value.len, llcf->access_src_key, "=access_by_lua"); @@ -191,7 +191,7 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->access_src_key); + rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->access_src_key); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 60c2267ea5..d224cb05c7 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -160,7 +160,7 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->body_filter_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->body_filter_src.value.data, llcf->body_filter_src.value.len, llcf->body_filter_src_key, "=body_filter_by_lua"); @@ -208,7 +208,7 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, + rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->body_filter_src_key); if (rc != NGX_OK) { return NGX_ERROR; diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index b75bf8de38..d154f143f0 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -32,8 +32,12 @@ * * */ static ngx_int_t -ngx_http_lua_cache_load_code(lua_State *L, const char *key) +ngx_http_lua_cache_load_code(ngx_http_request_t *r, lua_State *L, + const char *key) { + int rc; + u_char *err; + /* get code cache table */ lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */ @@ -49,14 +53,26 @@ ngx_http_lua_cache_load_code(lua_State *L, const char *key) if (lua_isfunction(L, -1)) { /* call closure factory to gen new closure */ - int rc = lua_pcall(L, 0, 1, 0); - + rc = lua_pcall(L, 0, 1, 0); if (rc == 0) { /* remove cache table from stack, leave code chunk at * top of stack */ lua_remove(L, -2); /* sp-- */ return NGX_OK; } + + if (lua_isstring(L, -1)) { + err = (u_char *) lua_tostring(L, -1); + + } else { + err = (u_char *) "unknown error"; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua: failed to run factory at key \"%s\": %s", + key, err); + lua_pop(L, 2); + return NGX_ERROR; } dd("Value associated with given key in code cache table is not code " @@ -117,23 +133,32 @@ ngx_http_lua_cache_store_code(lua_State *L, const char *key) ngx_int_t -ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, - const u_char *cache_key, const char *name) +ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, + const u_char *src, size_t src_len, const u_char *cache_key, + const char *name) { - int rc, n; + int n; + ngx_int_t rc; const char *err = NULL; n = lua_gettop(L); dd("XXX cache key: [%s]", cache_key); - if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == NGX_OK) { + rc = ngx_http_lua_cache_load_code(r, L, (char *) cache_key); + if (rc == NGX_OK) { /* code chunk loaded from cache, sp++ */ dd("Code cache hit! cache key='%s', stack top=%d, script='%.*s'", cache_key, lua_gettop(L), (int) src_len, src); return NGX_OK; } + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + /* rc == NGX_DECLINED */ + dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'", cache_key, lua_gettop(L), (int) src_len, src); @@ -160,7 +185,6 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, /* store closure factory and gen new closure at the top of lua stack to * code cache */ rc = ngx_http_lua_cache_store_code(L, (char *) cache_key); - if (rc != NGX_OK) { err = "fail to generate new closure from the closure factory"; goto error; @@ -169,7 +193,7 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, return NGX_OK; error: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to load inlined Lua code: %s", err); lua_settop(L, n); return NGX_ERROR; @@ -177,10 +201,11 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, ngx_int_t -ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, - const u_char *cache_key) +ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, + const u_char *script, const u_char *cache_key) { - int rc, n; + int n; + ngx_int_t rc; u_char *p; u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1]; const char *err = NULL; @@ -203,13 +228,20 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, dd("XXX cache key for file: [%s]", cache_key); - if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == NGX_OK) { + rc = ngx_http_lua_cache_load_code(r, L, (char *) cache_key); + if (rc == NGX_OK) { /* code chunk loaded from cache, sp++ */ dd("Code cache hit! cache key='%s', stack top=%d, file path='%s'", cache_key, lua_gettop(L), script); return NGX_OK; } + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + /* rc == NGX_DECLINED */ + dd("Code cache missed! cache key='%s', stack top=%d, file path='%s'", cache_key, lua_gettop(L), script); @@ -236,7 +268,6 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, /* store closure factory and gen new closure at the top of lua stack * to code cache */ rc = ngx_http_lua_cache_store_code(L, (char *) cache_key); - if (rc != NGX_OK) { err = "fail to generate new closure from the closure factory"; goto error; @@ -245,8 +276,8 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, return NGX_OK; error: - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, - "failed to load external Lua file: %s", err); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to load external Lua file \"%s\": %s", script, err); lua_settop(L, n); return NGX_ERROR; diff --git a/src/ngx_http_lua_cache.h b/src/ngx_http_lua_cache.h index cd2a25b8cd..64c4aa2091 100644 --- a/src/ngx_http_lua_cache.h +++ b/src/ngx_http_lua_cache.h @@ -12,10 +12,11 @@ #include "ngx_http_lua_common.h" -ngx_int_t ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, - size_t src_len, const u_char *cache_key, const char *name); -ngx_int_t ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, - const u_char *cache_key); +ngx_int_t ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, + const u_char *src, size_t src_len, const u_char *cache_key, + const char *name); +ngx_int_t ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, + const u_char *script, const u_char *cache_key); #endif /* _NGX_HTTP_LUA_CACHE_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index e0e8ae14c5..4487251aa4 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -330,7 +330,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, int x = 1, size_of_int, size_of_size_t, little_endian, size_of_inst, version, stripped; static int num_of_inst = 3, num_of_inter_func = 1; - const char *filename, *emsg, *serr, *bytecode; + const char *emsg, *serr, *bytecode; size_t size, bytecode_len; long fsize; @@ -577,13 +577,11 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, fclose(lf->f); /* close file (even in case of errors) */ - filename = lua_tostring(L, fname_index) + 1; - if (serr) { - lua_pushfstring(L, "%s in %s: %s", emsg, filename, serr); + lua_pushfstring(L, "%s: %s", emsg, serr); } else { - lua_pushfstring(L, "%s in %s", emsg, filename); + lua_pushstring(L, emsg); } lua_remove(L, fname_index); @@ -592,7 +590,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, } -int +ngx_int_t ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) { int c, status, readstatus; @@ -714,7 +712,7 @@ ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename) } -int +ngx_int_t ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, size_t size, const char *name) { diff --git a/src/ngx_http_lua_clfactory.h b/src/ngx_http_lua_clfactory.h index 7c1a4c3e1a..806d8afaae 100644 --- a/src/ngx_http_lua_clfactory.h +++ b/src/ngx_http_lua_clfactory.h @@ -12,8 +12,8 @@ #include "ngx_http_lua_common.h" -int ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename); -int ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, +ngx_int_t ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename); +ngx_int_t ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, size_t size, const char *name); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 15aeef0ab6..43bc6559a4 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -248,7 +248,8 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->content_src_key); + rc = ngx_http_lua_cache_loadfile(r, L, script_path, + llcf->content_src_key); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -272,7 +273,7 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->content_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->content_src.value.data, llcf->content_src.value.len, llcf->content_src_key, "=content_by_lua"); diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index b4af52f1c5..b9c9b02227 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -296,7 +296,7 @@ ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, ngx_str_t *val, L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, filter_data->script.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, filter_data->script.data, filter_data->script.len, filter_data->key, "=set_by_lua"); if (rc != NGX_OK) { @@ -349,7 +349,7 @@ ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, ngx_str_t *val, L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, filter_data->key); + rc = ngx_http_lua_cache_loadfile(r, L, script_path, filter_data->key); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index 9aa22dc019..ab66ff7d3c 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -176,7 +176,8 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->header_filter_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, + llcf->header_filter_src.value.data, llcf->header_filter_src.value.len, llcf->header_filter_src_key, "=header_filter_by_lua"); @@ -218,7 +219,7 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, + rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->header_filter_src_key); if (rc != NGX_OK) { return NGX_ERROR; diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 37fabb85e3..2960cbea64 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -125,7 +125,7 @@ ngx_http_lua_log_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->log_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->log_src.value.data, llcf->log_src.value.len, llcf->log_src_key, "=log_by_lua"); if (rc != NGX_OK) { @@ -161,7 +161,7 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->log_src_key); + rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->log_src_key); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 057ea416fa..efb40acdd7 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -154,7 +154,7 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua inline script (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadbuffer(L, llcf->rewrite_src.value.data, + rc = ngx_http_lua_cache_loadbuffer(r, L, llcf->rewrite_src.value.data, llcf->rewrite_src.value.len, llcf->rewrite_src_key, "=rewrite_by_lua"); @@ -191,7 +191,7 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) L = ngx_http_lua_get_lua_vm(r, NULL); /* load Lua script file (w/ cache) sp = 1 */ - rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->rewrite_src_key); + rc = ngx_http_lua_cache_loadfile(r, L, script_path, llcf->rewrite_src_key); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/t/001-set.t b/t/001-set.t index defa33c9ff..73bc3a7e13 100644 --- a/t/001-set.t +++ b/t/001-set.t @@ -795,5 +795,5 @@ 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/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ diff --git a/t/002-content.t b/t/002-content.t index 06a95e08f7..e62fd2ad3e 100644 --- a/t/002-content.t +++ b/t/002-content.t @@ -800,7 +800,7 @@ 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/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ diff --git a/t/023-rewrite/sanity.t b/t/023-rewrite/sanity.t index 88694395cb..b42eea71bc 100644 --- a/t/023-rewrite/sanity.t +++ b/t/023-rewrite/sanity.t @@ -754,5 +754,5 @@ 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/ +qr/failed to load external Lua file ".*?\btest2\.lua": cannot open .*? No such file or directory/ diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index acb7856eb8..51baeee65e 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -696,5 +696,5 @@ 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/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ diff --git a/t/041-header-filter.t b/t/041-header-filter.t index 3254a3e23d..b81d5af341 100644 --- a/t/041-header-filter.t +++ b/t/041-header-filter.t @@ -765,5 +765,5 @@ ngx.print("request_uri: ", v, "\n") GET /lua?a=1&b=2 --- ignore_response --- error_log eval -qr/failed to load external Lua file: cannot open .*? No such file or directory/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ diff --git a/t/075-logby.t b/t/075-logby.t index 2b4fa460e1..6d2de8d9e3 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -535,7 +535,7 @@ GET /lua?a=1&b=2 --- response_body ok --- error_log eval -qr/failed to load external Lua file: cannot open .*? No such file or directory/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ diff --git a/t/081-bytecode.t b/t/081-bytecode.t index 6954523381..6612235d90 100644 --- a/t/081-bytecode.t +++ b/t/081-bytecode.t @@ -85,8 +85,8 @@ __DATA__ \x1b\x4c\x4a\x01\x02\x29\x02\x00\x02\x00\x03\x00\x05\x34\x00\x00\x00\x37\x00\x01\x00\x25\x01\x02\x00\x3e\x00\x02\x01\x47\x00\x01\x00\x0a\x68\x65\x6c\x6c\x6f\x08\x73\x61\x79\x08\x6e\x67\x78\x00" --- response_body error ---- error_log -failed to load external Lua file: bad byte-code header in +--- error_log eval +qr/failed to load external Lua file ".*?test\.lua": bad byte-code header/ diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 0d93107c9d..5b795357b7 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -523,7 +523,7 @@ ngx.print("request_uri: ", v, "\n") GET /lua?a=1&b=2 --- ignore_response --- error_log eval -qr/failed to load external Lua file: cannot open .*? No such file or directory/ +qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ From cbf054f12ce60a58bafd8025e2594df77abe5d09 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 30 Mar 2014 20:45:49 -0700 Subject: [PATCH 0506/1981] made a test case less likely to fail on slow machines. --- t/109-timer-hup.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 98e9cb1e6b..0982cb03af 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -318,7 +318,7 @@ GET /t --- response_body ok ---- wait: 0.3 +--- wait: 0.5 --- no_error_log [error] [alert] From 3f7e04cf8e75a8e5ffdfbc2a70e36893cd357c57 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 30 Mar 2014 20:47:05 -0700 Subject: [PATCH 0507/1981] made a test case less likely to fail on slow machines. --- t/108-timer-safe.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/108-timer-safe.t b/t/108-timer-safe.t index dd77f4043d..2a844c91dd 100644 --- a/t/108-timer-safe.t +++ b/t/108-timer-safe.t @@ -108,7 +108,7 @@ delete thread 2 --- response_body registered timer ---- wait: 0.12 +--- wait: 0.5 --- no_error_log [error] [alert] From f08bddccd80f40af464de65b6e47b486c812242d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 30 Mar 2014 21:50:57 -0700 Subject: [PATCH 0508/1981] suppressed a false positive in libdl. --- valgrind.suppress | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/valgrind.suppress b/valgrind.suppress index 5ced95ef6c..36ecf14815 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -119,3 +119,16 @@ fun:main fun:ngx_master_process_cycle fun:main } +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start +} From 988ac5d84e06a6e599b0bd70f3a278c6326e2404 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 31 Mar 2014 13:07:59 -0700 Subject: [PATCH 0509/1981] bugfix: when lua_code_cache was off, cosocket:setkeepalive() might lead to segmentation faults. thanks Kelvin Peng for the report. --- src/ngx_http_lua_socket_tcp.c | 37 ++++++++++++++++++++ t/014-bugs.t | 63 ++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 47efd2c1ba..9f13aed74e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -104,6 +104,7 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r); static void ngx_http_lua_tcp_resolve_cleanup(void *data); static void ngx_http_lua_coctx_cleanup(void *data); +static int ngx_http_lua_socket_shutdown_pool(lua_State *L); enum { @@ -3643,6 +3644,11 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) return luaL_error(L, "out of memory"); } + lua_createtable(L, 0, 1); /* metatable */ + lua_pushcfunction(L, ngx_http_lua_socket_shutdown_pool); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua tcp socket keepalive create connection pool for key" " \"%s\"", lua_tostring(L, -2)); @@ -3965,6 +3971,37 @@ ngx_http_lua_socket_free_pool(ngx_log_t *log, ngx_http_lua_socket_pool_t *spool) } +static int +ngx_http_lua_socket_shutdown_pool(lua_State *L) +{ + ngx_queue_t *q; + ngx_connection_t *c; + ngx_http_lua_socket_pool_t *spool; + ngx_http_lua_socket_pool_item_t *item; + + spool = lua_touserdata(L, 1); + if (spool == NULL) { + return 0; + } + + while (!ngx_queue_empty(&spool->cache)) { + q = ngx_queue_head(&spool->cache); + + item = ngx_queue_data(q, ngx_http_lua_socket_pool_item_t, queue); + c = item->connection; + + ngx_close_connection(c); + + ngx_queue_remove(q); + ngx_queue_insert_head(&spool->free, q); + } + + spool->active_connections = 0; + + return 0; +} + + static int ngx_http_lua_socket_tcp_upstream_destroy(lua_State *L) { diff --git a/t/014-bugs.t b/t/014-bugs.t index a7be5d98c6..35f24f8915 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -9,11 +9,14 @@ log_level('debug'); repeat_each(3); -plan tests => repeat_each() * (blocks() * 2 + 26); +plan tests => repeat_each() * (blocks() * 2 + 27); our $HtmlDir = html_dir; #warn $html_dir; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; +$ENV{TEST_NGINX_REDIS_PORT} ||= 6379; + #no_diff(); #no_long_string(); @@ -872,3 +875,61 @@ args: foo=1&bar=2 [error] --- no_check_leak + + +=== TEST 39: lua_code_cache off + setkeepalive +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" +--- config + lua_code_cache off; + location = /t { + set $port $TEST_NGINX_REDIS_PORT; + content_by_lua ' + local test = require "test" + local port = ngx.var.port + test.go(port) + '; + } +--- user_files +>>> test.lua +module("test", package.seeall) + +function go(port) + local sock = ngx.socket.tcp() + local sock2 = ngx.socket.tcp() + + sock:settimeout(1000) + sock2:settimeout(6000000) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local ok, err = sock2:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local ok, err = sock:setkeepalive(100, 100) + if not ok then + ngx.say("failed to set reusable: ", err) + end + + local ok, err = sock2:setkeepalive(200, 100) + if not ok then + ngx.say("failed to set reusable: ", err) + end + + ngx.say("done") +end +--- request +GET /t +--- response_body +done +--- wait: 0.5 +--- no_error_log +[error] + From 5c788b8b985544d26d7c54c3295dbebc0608ffa4 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 31 Mar 2014 14:54:09 -0700 Subject: [PATCH 0510/1981] refactor: we no longer call ngx_pfree() in our own pcre_free hook. --- src/ngx_http_lua_pcrefix.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_pcrefix.c b/src/ngx_http_lua_pcrefix.c index 562847a639..ebd84f005f 100644 --- a/src/ngx_http_lua_pcrefix.c +++ b/src/ngx_http_lua_pcrefix.c @@ -42,16 +42,9 @@ ngx_http_lua_pcre_malloc(size_t size) static void -ngx_http_lua_pcre_free(void *ptr) +ngx_http_lua_pcre_free(void *p) { - dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); - - if (ngx_http_lua_pcre_pool) { - ngx_pfree(ngx_http_lua_pcre_pool, ptr); - return; - } - - fprintf(stderr, "error: lua pcre free failed due to empty pcre pool"); + return; } From 5c27180048c0910f724e16f77446ef79795c76cf Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 31 Mar 2014 14:54:39 -0700 Subject: [PATCH 0511/1981] added assertions for the pcre pool management. --- src/ngx_http_lua_logby.c | 1 + src/ngx_http_lua_setby.c | 1 + src/ngx_http_lua_util.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 2960cbea64..19a12e82fc 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -191,6 +191,7 @@ ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r) #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); + ngx_http_lua_assert(old_pool == NULL); #endif lua_pushcfunction(L, ngx_http_lua_traceback); diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index ed9ccc4942..6a1235a24d 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -69,6 +69,7 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); + ngx_http_lua_assert(old_pool == NULL); #endif lua_pushcfunction(L, ngx_http_lua_traceback); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0a5823bd42..6780950794 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1094,6 +1094,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); + ngx_http_lua_assert(old_pool == NULL); #endif /* run code */ From 4e284f73cc55d8e1a443e90006b652dbff9cf154 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 31 Mar 2014 14:55:28 -0700 Subject: [PATCH 0512/1981] bumped version to 0.9.7. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 83e5915902..a9a17a4f6d 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9006 +#define ngx_http_lua_version 9007 typedef struct { From 8192b9745f4c9dde0c3cb4ab8d212f989d8a8c94 Mon Sep 17 00:00:00 2001 From: lhmwzy Date: Tue, 1 Apr 2014 08:04:30 +0800 Subject: [PATCH 0513/1981] Update ngx_http_lua_string.c --- src/ngx_http_lua_string.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 7bd65ef65f..576b09ce57 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -1,4 +1,3 @@ - /* * Copyright (C) Xiaozhe Wang (chaoslawful) * Copyright (C) Yichun Zhang (agentzh) @@ -578,7 +577,7 @@ ngx_http_lua_ngx_hmac_sha1(lua_State *L) const EVP_MD *evp_md; if (lua_gettop(L) != 2) { - return luaL_error(L, "expecting one argument, but got %d", + return luaL_error(L, "expecting 2 arguments, but got %d", lua_gettop(L)); } From 40691f409a8ef37ef4627e7f3173fb151040cf41 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 2 Apr 2014 14:38:17 -0700 Subject: [PATCH 0514/1981] Revert "added assertions for the pcre pool management." This reverts commit 5c27180048c0910f724e16f77446ef79795c76cf. --- src/ngx_http_lua_logby.c | 1 - src/ngx_http_lua_setby.c | 1 - src/ngx_http_lua_util.c | 1 - 3 files changed, 3 deletions(-) diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 19a12e82fc..2960cbea64 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -191,7 +191,6 @@ ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r) #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); - ngx_http_lua_assert(old_pool == NULL); #endif lua_pushcfunction(L, ngx_http_lua_traceback); diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 6a1235a24d..ed9ccc4942 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -69,7 +69,6 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); - ngx_http_lua_assert(old_pool == NULL); #endif lua_pushcfunction(L, ngx_http_lua_traceback); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 6780950794..0a5823bd42 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1094,7 +1094,6 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); - ngx_http_lua_assert(old_pool == NULL); #endif /* run code */ From e52a2631ecd1f7807e7715936d4a9ede72ceb8b5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 6 Apr 2014 17:04:11 -0700 Subject: [PATCH 0515/1981] doc: now we have tested with nginx 1.5.12; also put the 0.9.7 release date. --- README.markdown | 10 +++++----- doc/HttpLuaModule.wiki | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.markdown b/README.markdown index 8fccf94696..7641fc5554 100644 --- a/README.markdown +++ b/README.markdown @@ -221,7 +221,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.9.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 March 2014. +This document describes ngx_lua [v0.9.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 6 April 2014. Synopsis ======== @@ -6408,7 +6408,7 @@ Nginx Compatibility =================== The latest module is compatible with the following versions of Nginx: -* 1.5.x (last tested: 1.5.11) +* 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) @@ -6442,9 +6442,9 @@ Build the source with this module: ```bash -wget 'http://nginx.org/download/nginx-1.5.11.tar.gz' -tar -xzvf nginx-1.5.11.tar.gz -cd nginx-1.5.11/ +wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' +tar -xzvf nginx-1.5.12.tar.gz +cd nginx-1.5.12/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 3669cce29a..8ac2c85fa1 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.6] released on 20 March 2014. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.7] released on 6 April 2014. = Synopsis = @@ -5432,7 +5432,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The latest module is compatible with the following versions of Nginx: -* 1.5.x (last tested: 1.5.11) +* 1.5.x (last tested: 1.5.12) * 1.4.x (last tested: 1.4.4) * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.9) @@ -5459,9 +5459,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.5.11.tar.gz' - tar -xzvf nginx-1.5.11.tar.gz - cd nginx-1.5.11/ + wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' + tar -xzvf nginx-1.5.12.tar.gz + cd nginx-1.5.12/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib From 0375856d8f1e11a998fe7f5f945414663e661e4e Mon Sep 17 00:00:00 2001 From: cubicdaiya Date: Mon, 7 Apr 2014 19:37:12 +0900 Subject: [PATCH 0516/1981] use ngx_str_null --- src/ngx_http_lua_control.c | 6 ++---- src/ngx_http_lua_headers.c | 12 ++++-------- src/ngx_http_lua_shdict.c | 3 +-- src/ngx_http_lua_subrequest.c | 6 ++---- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 41a9b7f36f..5e301fd5e1 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -74,8 +74,7 @@ ngx_http_lua_ngx_exec(lua_State *L) return luaL_error(L, "no request object found"); } - args.data = NULL; - args.len = 0; + ngx_str_null(&args); /* read the 1st argument (uri) */ @@ -138,8 +137,7 @@ ngx_http_lua_ngx_exec(lua_State *L) break; case LUA_TNIL: - user_args.data = NULL; - user_args.len = 0; + ngx_str_null(&user_args); break; default: diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 55c6efc932..0703b9c525 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -629,14 +629,12 @@ ngx_http_lua_ngx_header_set(lua_State *L) } if (lua_type(L, 3) == LUA_TNIL) { - value.data = NULL; - value.len = 0; + ngx_str_null(&value); } else if (lua_type(L, 3) == LUA_TTABLE) { n = luaL_getn(L, 3); if (n == 0) { - value.data = NULL; - value.len = 0; + ngx_str_null(&value); } else { for (i = 1; i <= n; i++) { @@ -765,14 +763,12 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) key.len = len; if (lua_type(L, 2) == LUA_TNIL) { - value.data = NULL; - value.len = 0; + ngx_str_null(&value); } else if (lua_type(L, 2) == LUA_TTABLE) { n = luaL_getn(L, 2); if (n == 0) { - value.data = NULL; - value.len = 0; + ngx_str_null(&value); } else { for (i = 1; i <= n; i++) { diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 13fdbbee23..74e26b6c63 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -890,8 +890,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) return 2; } - value.len = 0; - value.data = NULL; + ngx_str_null(&value); break; default: diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index efa5906008..3f15c99cb9 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -243,8 +243,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) body = NULL; - extra_args.data = NULL; - extra_args.len = 0; + ngx_str_null(&extra_args); if (extra_vars != NULL) { /* flush out existing elements in the array */ @@ -487,8 +486,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) uri.len = len; - args.data = NULL; - args.len = 0; + ngx_str_null(&args); flags = 0; From 0d48124c9d65e8f6c2618fc1e9b5f9a8dc59b4ce Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 8 Apr 2014 21:48:05 -0700 Subject: [PATCH 0517/1981] added a (passing) test for timeout error on tcpsock:receive(N). --- t/065-tcp-socket-timeout.t | 41 +++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index e373abcb53..d5f9a50a39 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -29,7 +29,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 12); +plan tests => repeat_each() * (blocks() * 4 + 13); our $HtmlDir = html_dir; @@ -879,3 +879,42 @@ quitting request now lua tcp socket write timed out [alert] + + +=== TEST 21: read timeout on receive(N) +--- config + server_tokens off; + lua_socket_read_timeout 100ms; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + sock:settimeout(10) + + local line + line, err = sock:receive(3) + if line then + ngx.say("received: ", line) + else + ngx.say("failed to receive: ", err) + end + '; + } +--- request +GET /t +--- response_body +connected: 1 +failed to receive: timeout +--- error_log +lua tcp socket read timeout: 10 +lua tcp socket connect timeout: 60000 +lua tcp socket read timed out + From b111180c179b3292c8a3445f2c942cbbdc76ec69 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 12 Apr 2014 19:11:15 -0700 Subject: [PATCH 0518/1981] added a (passing) test case for reading ngx.header in the context of log_by_lua. --- t/075-logby.t | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/t/075-logby.t b/t/075-logby.t index 6d2de8d9e3..3a4cc478fc 100644 --- a/t/075-logby.t +++ b/t/075-logby.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 9); +plan tests => repeat_each() * (blocks() * 3 + 10); #no_diff(); #no_long_string(); @@ -564,3 +564,21 @@ ok --- no_error_log [error] + + +=== TEST 31: reading ngx.header.HEADER in log_by_lua +--- config + location /lua { + echo ok; + log_by_lua 'ngx.log(ngx.WARN, "content-type: ", ngx.header.content_type)'; + } +--- request +GET /lua + +--- response_body +ok +--- error_log +log_by_lua:1: content-type: text/plain +--- no_error_log +[error] + From c11ceb40ad2c7d6241624641dae55e992de53230 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 22 Apr 2014 13:43:23 -0700 Subject: [PATCH 0519/1981] updated the tests to reflect the new openresty server at agentzh.org. --- t/023-rewrite/tcp-socket.t | 2 +- t/058-tcp-socket.t | 2 +- t/124-init-worker.t | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index ca5bf22081..86566d0ff0 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -255,7 +255,7 @@ GET /t connected: 1 request sent: 56 first line received: HTTP/1.1 200 OK -second line received: Server: ngx_openresty +second line received: Server: openresty --- no_error_log [error] diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 5ffcd81ff6..c61fd170c6 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -250,7 +250,7 @@ GET /t connected: 1 request sent: 56 first line received: HTTP/1.1 200 OK -second line received: Server: ngx_openresty +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 diff --git a/t/124-init-worker.t b/t/124-init-worker.t index 8b6545a3ad..fb56b81dc4 100644 --- a/t/124-init-worker.t +++ b/t/124-init-worker.t @@ -524,7 +524,7 @@ timer created connected: 1 request sent: 56 first line received: HTTP/1.1 200 OK -second line received: Server: ngx_openresty +second line received: Server: openresty --- no_error_log [error] --- timeout: 10 From 6c555ed505d29b2dba9541a6a28fbc5cf9a11928 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 30 Apr 2014 12:07:27 -0700 Subject: [PATCH 0520/1981] bugfix: bugs in the error handling for pure C API functions for shared dict. thanks Xiaochen Wang for the patch in #365. --- src/ngx_http_lua_shdict.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 74e26b6c63..16acf0d0e5 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1270,6 +1270,7 @@ ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, if (value->value.s.data == NULL || value->value.s.len == 0) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer " "initialized"); + ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } @@ -1721,6 +1722,7 @@ ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, "bad value type found for key %*s in " "shared_dict %V: %d", key_len, key, &name, *value_type); + return NGX_ERROR; } *user_flags = sd->user_flags; From 39d3e74cbcb2dc91e7870a014bb93bd0ae39f73f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 30 Apr 2014 12:20:54 -0700 Subject: [PATCH 0521/1981] updated docs to reflect recent changes. --- README.markdown | 131 +++++++++++++++++++++-------------------- doc/HttpLuaModule.wiki | 79 +++++++++++++------------ 2 files changed, 108 insertions(+), 102 deletions(-) diff --git a/README.markdown b/README.markdown index 7641fc5554..997d636987 100644 --- a/README.markdown +++ b/README.markdown @@ -221,7 +221,7 @@ This module is under active development and is production ready. Version ======= -This document describes ngx_lua [v0.9.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 6 April 2014. +This document describes ngx_lua [v0.9.7](https://github.com/openresty/lua-nginx-module/tags) released on 6 April 2014. Synopsis ======== @@ -406,17 +406,17 @@ requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or up At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: -* [lua-resty-memcached](https://github.com/agentzh/lua-resty-memcached) -* [lua-resty-mysql](https://github.com/agentzh/lua-resty-mysql) -* [lua-resty-redis](https://github.com/agentzh/lua-resty-redis) -* [lua-resty-dns](https://github.com/agentzh/lua-resty-dns) -* [lua-resty-upload](https://github.com/agentzh/lua-resty-upload) -* [lua-resty-websocket](https://github.com/agentzh/lua-resty-websocket) -* [lua-resty-lock](https://github.com/agentzh/lua-resty-lock) -* [lua-resty-string](https://github.com/agentzh/lua-resty-string) -* [ngx_memc](http://github.com/agentzh/memc-nginx-module) +* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) +* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) +* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) +* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) +* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) +* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) +* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) +* [lua-resty-string](https://github.com/openresty/lua-resty-string) +* [ngx_memc](http://github.com/openresty/memc-nginx-module) * [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) -* [ngx_redis2](http://github.com/agentzh/redis2-nginx-module) +* [ngx_redis2](http://github.com/openresty/redis2-nginx-module) * [ngx_redis](http://wiki.nginx.org/HttpRedisModule) * [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) * [ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) @@ -712,19 +712,22 @@ set_by_lua **context:** *server, server if, location, location if* -**phase:** *server-rewrite, rewrite* +**phase:** *rewrite* Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. -Note that the following API functions are currently disabled within this context: +This directive is implemented by injecting custom commands into the standard HttpRewriteModule's command list. Because HttpRewriteModule does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. + +At least the following API functions are currently disabled within the context of `set_by_lua`: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) * Control API functions (e.g., [ngx.exit](#ngxexit)) * Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) * Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). +* Sleeping API function [ngx.sleep](#ngxsleep). In addition, note that this directive can only write out a value to a single Nginx variable at a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. @@ -746,7 +749,7 @@ location /foo { } ``` -This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/agentzh/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/agentzh/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. +This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. ```nginx @@ -767,7 +770,7 @@ set_by_lua_file **context:** *server, server if, location, location if* -**phase:** *server-rewrite, rewrite* +**phase:** *rewrite* Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. @@ -3295,7 +3298,7 @@ Since the `v0.9.0` release, this function accepts an optional boolean `raw` argu When the `raw` argument is `true`, it is required that no pending data from any previous [ngx.say](#ngxsay), [ngx.print](#ngxprint), or [ngx.send_headers](#ngxsend_headers) calls exists. So if you have these downstream output calls previously, you should call [ngx.flush(true)](#ngxflush) before calling `ngx.req.socket(true)` to ensure that there is no pending output data. If the request body has not been read yet, then this "raw socket" can also be used to read the request body. -You can use the "raw request socket" returned by `ngx.req.socket(true)` to implement fancy protocols like [WebSocket](http://en.wikipedia.org/wiki/WebSocket), or just emit your own raw HTTP response header or body data. You can refer to the [lua-resty-websocket library](https://github.com/agentzh/lua-resty-websocket) for a real world example. +You can use the "raw request socket" returned by `ngx.req.socket(true)` to implement fancy protocols like [WebSocket](http://en.wikipedia.org/wiki/WebSocket), or just emit your own raw HTTP response header or body data. You can refer to the [lua-resty-websocket library](https://github.com/openresty/lua-resty-websocket) for a real world example. This function was first introduced in the `v0.5.0rc1` release. @@ -3357,7 +3360,7 @@ outputs by either [ngx.print](#ngxprint) or [ngx.say](#ngxsay). It is strongly recommended to combine the `return` statement with this call, i.e., `return ngx.exec(...)`. -This method is similar to the [echo_exec](http://github.com/agentzh/echo-nginx-module#echo_exec) directive of the [echo-nginx-module](http://github.com/agentzh/echo-nginx-module). +This method is similar to the [echo_exec](http://github.com/openresty/echo-nginx-module#echo_exec) directive of the [echo-nginx-module](http://github.com/openresty/echo-nginx-module). [Back to TOC](#table-of-contents) @@ -5852,21 +5855,21 @@ ndk.set_var.DIRECTIVE This mechanism allows calling other nginx C modules' directives that are implemented by [Nginx Devel Kit](https://github.com/simpl/ngx_devel_kit) (NDK)'s set_var submodule's `ndk_set_var_value`. -For example, the following [set-misc-nginx-module](http://github.com/agentzh/set-misc-nginx-module) directives can be invoked this way: - -* [set_quote_sql_str](http://github.com/agentzh/set-misc-nginx-module#set_quote_sql_str) -* [set_quote_pgsql_str](http://github.com/agentzh/set-misc-nginx-module#set_quote_pgsql_str) -* [set_quote_json_str](http://github.com/agentzh/set-misc-nginx-module#set_quote_json_str) -* [set_unescape_uri](http://github.com/agentzh/set-misc-nginx-module#set_unescape_uri) -* [set_escape_uri](http://github.com/agentzh/set-misc-nginx-module#set_escape_uri) -* [set_encode_base32](http://github.com/agentzh/set-misc-nginx-module#set_encode_base32) -* [set_decode_base32](http://github.com/agentzh/set-misc-nginx-module#set_decode_base32) -* [set_encode_base64](http://github.com/agentzh/set-misc-nginx-module#set_encode_base64) -* [set_decode_base64](http://github.com/agentzh/set-misc-nginx-module#set_decode_base64) -* [set_encode_hex](http://github.com/agentzh/set-misc-nginx-module#set_encode_base64) -* [set_decode_hex](http://github.com/agentzh/set-misc-nginx-module#set_decode_base64) -* [set_sha1](http://github.com/agentzh/set-misc-nginx-module#set_encode_base64) -* [set_md5](http://github.com/agentzh/set-misc-nginx-module#set_decode_base64) +For example, the following [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module) directives can be invoked this way: + +* [set_quote_sql_str](http://github.com/openresty/set-misc-nginx-module#set_quote_sql_str) +* [set_quote_pgsql_str](http://github.com/openresty/set-misc-nginx-module#set_quote_pgsql_str) +* [set_quote_json_str](http://github.com/openresty/set-misc-nginx-module#set_quote_json_str) +* [set_unescape_uri](http://github.com/openresty/set-misc-nginx-module#set_unescape_uri) +* [set_escape_uri](http://github.com/openresty/set-misc-nginx-module#set_escape_uri) +* [set_encode_base32](http://github.com/openresty/set-misc-nginx-module#set_encode_base32) +* [set_decode_base32](http://github.com/openresty/set-misc-nginx-module#set_decode_base32) +* [set_encode_base64](http://github.com/openresty/set-misc-nginx-module#set_encode_base64) +* [set_decode_base64](http://github.com/openresty/set-misc-nginx-module#set_decode_base64) +* [set_encode_hex](http://github.com/openresty/set-misc-nginx-module#set_encode_base64) +* [set_decode_hex](http://github.com/openresty/set-misc-nginx-module#set_decode_base64) +* [set_sha1](http://github.com/openresty/set-misc-nginx-module#set_encode_base64) +* [set_md5](http://github.com/openresty/set-misc-nginx-module#set_decode_base64) For instance, @@ -5876,10 +5879,10 @@ local res = ndk.set_var.set_escape_uri('a/b'); -- now res == 'a%2fb' ``` -Similarly, the following directives provided by [encrypted-session-nginx-module](http://github.com/agentzh/encrypted-session-nginx-module) can be invoked from within Lua too: +Similarly, the following directives provided by [encrypted-session-nginx-module](http://github.com/openresty/encrypted-session-nginx-module) can be invoked from within Lua too: -* [set_encrypt_session](http://github.com/agentzh/encrypted-session-nginx-module#set_encrypt_session) -* [set_decrypt_session](http://github.com/agentzh/encrypted-session-nginx-module#set_decrypt_session) +* [set_encrypt_session](http://github.com/openresty/encrypted-session-nginx-module#set_encrypt_session) +* [set_decrypt_session](http://github.com/openresty/encrypted-session-nginx-module#set_decrypt_session) This feature requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. @@ -6233,7 +6236,7 @@ Generally, use of Lua global variables is a really really bad idea in the contex It's *highly* recommended to always declare them via "local" in the scope that is reasonable. -To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/agentzh/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: +To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -6249,7 +6252,7 @@ This tool will guarantee that local variables in the Lua module functions are al Locations Configured by Subrequest Directives of Other Modules -------------------------------------------------------------- -The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [echo_location](http://github.com/agentzh/echo-nginx-module#echo_location), [echo_location_async](http://github.com/agentzh/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/agentzh/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/agentzh/echo-nginx-module#echo_subrequest_async) directives. +The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. ```nginx @@ -6422,7 +6425,7 @@ The latest module is compatible with the following versions of Nginx: Code Repository =============== -The code repository of this project is hosted on github at [chaoslawful/lua-nginx-module](http://github.com/chaoslawful/lua-nginx-module). +The code repository of this project is hosted on github at [openresty/lua-nginx-module](http://github.com/openresty/lua-nginx-module). [Back to TOC](#table-of-contents) @@ -6435,7 +6438,7 @@ Alternatively, ngx_lua can be manually compiled into Nginx: 1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. 1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](http://github.com/simpl/ngx_devel_kit/tags). -1. Download the latest version of ngx_lua [HERE](http://github.com/chaoslawful/lua-nginx-module/tags). +1. Download the latest version of ngx_lua [HERE](http://github.com/openresty/lua-nginx-module/tags). 1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) Build the source with this module: @@ -6516,7 +6519,7 @@ Bugs and Patches Please submit bug reports, wishlists, or patches by -1. creating a ticket on the [GitHub Issue Tracker](http://github.com/chaoslawful/lua-nginx-module/issues), +1. creating a ticket on the [GitHub Issue Tracker](http://github.com/openresty/lua-nginx-module/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) @@ -6562,22 +6565,22 @@ The following dependencies are required to run the test suite: * Nginx version >= 1.4.2 * Perl modules: - * Test::Nginx: + * Test::Nginx: * Nginx modules: * [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) - * [ngx_set_misc](http://github.com/agentzh/set-misc-nginx-module) + * [ngx_set_misc](http://github.com/openresty/set-misc-nginx-module) * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. - * [ngx_echo](http://github.com/agentzh/echo-nginx-module) - * [ngx_memc](http://github.com/agentzh/memc-nginx-module) - * [ngx_srcache](http://github.com/agentzh/srcache-nginx-module) + * [ngx_echo](http://github.com/openresty/echo-nginx-module) + * [ngx_memc](http://github.com/openresty/memc-nginx-module) + * [ngx_srcache](http://github.com/openresty/srcache-nginx-module) * ngx_lua (i.e., this module) - * [ngx_lua_upstream](http://github.com/agentzh/lua-upstream-nginx-module) - * [ngx_headers_more](http://github.com/agentzh/headers-more-nginx-module) - * [ngx_drizzle](http://github.com/chaoslawful/drizzle-nginx-module) - * [ngx_rds_json](http://github.com/agentzh/rds-json-nginx-module) + * [ngx_lua_upstream](http://github.com/openresty/lua-upstream-nginx-module) + * [ngx_headers_more](http://github.com/openresty/headers-more-nginx-module) + * [ngx_drizzle](http://github.com/openresty/drizzle-nginx-module) + * [ngx_rds_json](http://github.com/openresty/rds-json-nginx-module) * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) - * [ngx_redis2](http://github.com/agentzh/redis2-nginx-module) + * [ngx_redis2](http://github.com/openresty/redis2-nginx-module) The order in which these modules are added during configuration is important because the position of any filter module in the filtering chain determines the final output, for example. The correct adding order is shown above. @@ -6590,7 +6593,7 @@ filtering chain determines the final output, for example. The correct adding ord * memcached: listening on the default port, 11211. * redis: listening on the default port, 6379. -See also the [developer build script](https://github.com/chaoslawful/lua-nginx-module/blob/master/util/build2.sh) for more details on setting up the testing environment. +See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build2.sh) for more details on setting up the testing environment. To run the whole test suite in the default testing mode: @@ -6636,22 +6639,22 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND See Also ======== -* [lua-resty-memcached](http://github.com/agentzh/lua-resty-memcached) library based on ngx_lua cosocket. -* [lua-resty-redis](http://github.com/agentzh/lua-resty-redis) library based on ngx_lua cosocket. -* [lua-resty-mysql](http://github.com/agentzh/lua-resty-mysql) library based on ngx_lua cosocket. -* [lua-resty-upload](http://github.com/agentzh/lua-resty-upload) library based on ngx_lua cosocket. -* [lua-resty-dns](http://github.com/agentzh/lua-resty-dns) library based on ngx_lua cosocket. -* [lua-resty-websocket](http://github.com/agentzh/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. -* [lua-resty-string](http://github.com/agentzh/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). -* [lua-resty-lock](http://github.com/agentzh/lua-resty-lock) library for a nonblocking simple lock API. +* [lua-resty-memcached](http://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. +* [lua-resty-redis](http://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. +* [lua-resty-mysql](http://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. +* [lua-resty-upload](http://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. +* [lua-resty-dns](http://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. +* [lua-resty-websocket](http://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. +* [lua-resty-string](http://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). +* [lua-resty-lock](http://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. * [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) * [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) * [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) -* [Introduction to ngx_lua](https://github.com/chaoslawful/lua-nginx-module/wiki/Introduction) +* [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) * [ngx_devel_kit](http://github.com/simpl/ngx_devel_kit) -* [echo-nginx-module](http://github.com/agentzh/echo-nginx-module) -* [drizzle-nginx-module](http://github.com/chaoslawful/drizzle-nginx-module) +* [echo-nginx-module](http://github.com/openresty/echo-nginx-module) +* [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) * [postgres-nginx-module](http://github.com/FRiCKLE/ngx_postgres) -* [memc-nginx-module](http://github.com/agentzh/memc-nginx-module) +* [memc-nginx-module](http://github.com/openresty/memc-nginx-module) * [The ngx_openresty bundle](http://openresty.org) -* [Nginx Systemtap Toolkit](https://github.com/agentzh/nginx-systemtap-toolkit) +* [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 8ac2c85fa1..b198c12d18 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ This module is under active development and is production ready. = Version = -This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.9.7] released on 6 April 2014. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.9.7] released on 6 April 2014. = Synopsis = @@ -190,14 +190,14 @@ requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or up At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: -* [https://github.com/agentzh/lua-resty-memcached lua-resty-memcached] -* [https://github.com/agentzh/lua-resty-mysql lua-resty-mysql] -* [https://github.com/agentzh/lua-resty-redis lua-resty-redis] -* [https://github.com/agentzh/lua-resty-dns lua-resty-dns] -* [https://github.com/agentzh/lua-resty-upload lua-resty-upload] -* [https://github.com/agentzh/lua-resty-websocket lua-resty-websocket] -* [https://github.com/agentzh/lua-resty-lock lua-resty-lock] -* [https://github.com/agentzh/lua-resty-string lua-resty-string] +* [https://github.com/openresty/lua-resty-memcached lua-resty-memcached] +* [https://github.com/openresty/lua-resty-mysql lua-resty-mysql] +* [https://github.com/openresty/lua-resty-redis lua-resty-redis] +* [https://github.com/openresty/lua-resty-dns lua-resty-dns] +* [https://github.com/openresty/lua-resty-upload lua-resty-upload] +* [https://github.com/openresty/lua-resty-websocket lua-resty-websocket] +* [https://github.com/openresty/lua-resty-lock lua-resty-lock] +* [https://github.com/openresty/lua-resty-string lua-resty-string] * [[HttpMemcModule|ngx_memc]] * [https://github.com/FRiCKLE/ngx_postgres ngx_postgres] * [[HttpRedis2Module|ngx_redis2]] @@ -457,19 +457,22 @@ This directive was first introduced in the v0.9.5 release. '''context:''' ''server, server if, location, location if'' -'''phase:''' ''server-rewrite, rewrite'' +'''phase:''' ''rewrite'' Executes code specified in with optional input arguments $arg1 $arg2 ..., and returns string output to $res. The code in can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the ngx.arg table (index starts from 1 and increases sequentially). This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. -Note that the following API functions are currently disabled within this context: +This directive is implemented by injecting custom commands into the standard HttpRewriteModule's command list. Because HttpRewriteModule does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. + +At least the following API functions are currently disabled within the context of set_by_lua: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) * Control API functions (e.g., [[#ngx.exit|ngx.exit]]) * Subrequest API functions (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]]) * Cosocket API functions (e.g., [[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.req.socket|ngx.req.socket]]). +* Sleeping API function [[#ngx.sleep|ngx.sleep]]. In addition, note that this directive can only write out a value to a single Nginx variable at a time. However, a workaround is possible using the [[#ngx.var.VARIABLE|ngx.var.VARIABLE]] interface. @@ -507,7 +510,7 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki '''context:''' ''server, server if, location, location if'' -'''phase:''' ''server-rewrite, rewrite'' +'''phase:''' ''rewrite'' Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. @@ -2729,7 +2732,7 @@ Since the v0.9.0 release, this function accepts an optional boolean When the raw argument is true, it is required that no pending data from any previous [[#ngx.say|ngx.say]], [[#ngx.print|ngx.print]], or [[#ngx.send_headers|ngx.send_headers]] calls exists. So if you have these downstream output calls previously, you should call [[#ngx.flush|ngx.flush(true)]] before calling ngx.req.socket(true) to ensure that there is no pending output data. If the request body has not been read yet, then this "raw socket" can also be used to read the request body. -You can use the "raw request socket" returned by ngx.req.socket(true) to implement fancy protocols like [http://en.wikipedia.org/wiki/WebSocket WebSocket], or just emit your own raw HTTP response header or body data. You can refer to the [https://github.com/agentzh/lua-resty-websocket lua-resty-websocket library] for a real world example. +You can use the "raw request socket" returned by ngx.req.socket(true) to implement fancy protocols like [http://en.wikipedia.org/wiki/WebSocket WebSocket], or just emit your own raw HTTP response header or body data. You can refer to the [https://github.com/openresty/lua-resty-websocket lua-resty-websocket library] for a real world example. This function was first introduced in the v0.5.0rc1 release. @@ -5283,7 +5286,7 @@ Generally, use of Lua global variables is a really really bad idea in the contex It's *highly* recommended to always declare them via "local" in the scope that is reasonable. -To find out all the uses of Lua global variables in your Lua code, you can run the [https://github.com/agentzh/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all your .lua source files: +To find out all the uses of Lua global variables in your Lua code, you can run the [https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all your .lua source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -5443,7 +5446,7 @@ The latest module is compatible with the following versions of Nginx: = Code Repository = -The code repository of this project is hosted on github at [http://github.com/chaoslawful/lua-nginx-module chaoslawful/lua-nginx-module]. +The code repository of this project is hosted on github at [http://github.com/openresty/lua-nginx-module openresty/lua-nginx-module]. = Installation = @@ -5453,7 +5456,7 @@ Alternatively, ngx_lua can be manually compiled into Nginx: # Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuajIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. # Download the latest version of the ngx_devel_kit (NDK) module [http://github.com/simpl/ngx_devel_kit/tags HERE]. -# Download the latest version of ngx_lua [http://github.com/chaoslawful/lua-nginx-module/tags HERE]. +# Download the latest version of ngx_lua [http://github.com/openresty/lua-nginx-module/tags HERE]. # Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) Build the source with this module: @@ -5516,7 +5519,7 @@ The [https://groups.google.com/group/openresty openresty] mailing list is for Ch Please submit bug reports, wishlists, or patches by -# creating a ticket on the [http://github.com/chaoslawful/lua-nginx-module/issues GitHub Issue Tracker], +# creating a ticket on the [http://github.com/openresty/lua-nginx-module/issues GitHub Issue Tracker], # or posting to the [[#Community|OpenResty community]]. = TODO = @@ -5547,22 +5550,22 @@ The following dependencies are required to run the test suite: * Nginx version >= 1.4.2 * Perl modules: -** Test::Nginx: http://github.com/agentzh/test-nginx +** Test::Nginx: http://github.com/openresty/test-nginx * Nginx modules: ** [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] -** [http://github.com/agentzh/set-misc-nginx-module ngx_set_misc] +** [http://github.com/openresty/set-misc-nginx-module ngx_set_misc] ** [http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz ngx_auth_request] (this is not needed if you're using Nginx 1.5.4+. -** [http://github.com/agentzh/echo-nginx-module ngx_echo] -** [http://github.com/agentzh/memc-nginx-module ngx_memc] -** [http://github.com/agentzh/srcache-nginx-module ngx_srcache] +** [http://github.com/openresty/echo-nginx-module ngx_echo] +** [http://github.com/openresty/memc-nginx-module ngx_memc] +** [http://github.com/openresty/srcache-nginx-module ngx_srcache] ** ngx_lua (i.e., this module) -** [http://github.com/agentzh/lua-upstream-nginx-module ngx_lua_upstream] -** [http://github.com/agentzh/headers-more-nginx-module ngx_headers_more] -** [http://github.com/chaoslawful/drizzle-nginx-module ngx_drizzle] -** [http://github.com/agentzh/rds-json-nginx-module ngx_rds_json] +** [http://github.com/openresty/lua-upstream-nginx-module ngx_lua_upstream] +** [http://github.com/openresty/headers-more-nginx-module ngx_headers_more] +** [http://github.com/openresty/drizzle-nginx-module ngx_drizzle] +** [http://github.com/openresty/rds-json-nginx-module ngx_rds_json] ** [https://github.com/FRiCKLE/ngx_coolkit ngx_coolkit] -** [http://github.com/agentzh/redis2-nginx-module ngx_redis2] +** [http://github.com/openresty/redis2-nginx-module ngx_redis2] The order in which these modules are added during configuration is important because the position of any filter module in the filtering chain determines the final output, for example. The correct adding order is shown above. @@ -5575,7 +5578,7 @@ filtering chain determines the final output, for example. The correct adding ord ** memcached: listening on the default port, 11211. ** redis: listening on the default port, 6379. -See also the [https://github.com/chaoslawful/lua-nginx-module/blob/master/util/build2.sh developer build script] for more details on setting up the testing environment. +See also the [https://github.com/openresty/lua-nginx-module/blob/master/util/build2.sh developer build script] for more details on setting up the testing environment. To run the whole test suite in the default testing mode: @@ -5615,22 +5618,22 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND = See Also = -* [http://github.com/agentzh/lua-resty-memcached lua-resty-memcached] library based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-redis lua-resty-redis] library based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-upload lua-resty-upload] library based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-dns lua-resty-dns] library based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-websocket lua-resty-websocket] library for both WebSocket server and client, based on ngx_lua cosocket. -* [http://github.com/agentzh/lua-resty-string lua-resty-string] library based on [http://luajit.org/ext_ffi.html LuaJIT FFI]. -* [http://github.com/agentzh/lua-resty-lock lua-resty-lock] library for a nonblocking simple lock API. +* [http://github.com/openresty/lua-resty-memcached lua-resty-memcached] library based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-redis lua-resty-redis] library based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-mysql lua-resty-mysql] library based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-upload lua-resty-upload] library based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-dns lua-resty-dns] library based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-websocket lua-resty-websocket] library for both WebSocket server and client, based on ngx_lua cosocket. +* [http://github.com/openresty/lua-resty-string lua-resty-string] library based on [http://luajit.org/ext_ffi.html LuaJIT FFI]. +* [http://github.com/openresty/lua-resty-lock lua-resty-lock] library for a nonblocking simple lock API. * [http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs Routing requests to different MySQL queries based on URI arguments] * [http://openresty.org/#DynamicRoutingBasedOnRedis Dynamic Routing Based on Redis and Lua] * [http://openresty.org/#UsingLuaRocks Using LuaRocks with ngx_lua] -* [https://github.com/chaoslawful/lua-nginx-module/wiki/Introduction Introduction to ngx_lua] +* [https://github.com/openresty/lua-nginx-module/wiki/Introduction Introduction to ngx_lua] * [http://github.com/simpl/ngx_devel_kit ngx_devel_kit] * [[HttpEchoModule]] * [[HttpDrizzleModule]] * [http://github.com/FRiCKLE/ngx_postgres postgres-nginx-module] * [[HttpMemcModule]] * [http://openresty.org The ngx_openresty bundle] -* [https://github.com/agentzh/nginx-systemtap-toolkit Nginx Systemtap Toolkit] +* [https://github.com/openresty/nginx-systemtap-toolkit Nginx Systemtap Toolkit] From 506728da23abfa0391f3e600184808d10fe3ed42 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 30 Apr 2014 12:24:55 -0700 Subject: [PATCH 0522/1981] doc: fixed the links to ngx_rewrite in the "set_by_lua" section. --- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 997d636987..c8514b8ee7 100644 --- a/README.markdown +++ b/README.markdown @@ -719,7 +719,7 @@ The code in `` can make [API calls](#nginx-api-for-lua) and can This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. -This directive is implemented by injecting custom commands into the standard HttpRewriteModule's command list. Because HttpRewriteModule does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. +This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. At least the following API functions are currently disabled within the context of `set_by_lua`: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b198c12d18..7aa04e3c90 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -464,7 +464,7 @@ The code in can make [[#Nginx API for Lua|API call This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. -This directive is implemented by injecting custom commands into the standard HttpRewriteModule's command list. Because HttpRewriteModule does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. +This directive is implemented by injecting custom commands into the standard [[HttpRewriteModule]]'s command list. Because [[HttpRewriteModule]] does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. At least the following API functions are currently disabled within the context of set_by_lua: From 1255864049b9e12d776cca6765bd6b623dc61054 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 1 May 2014 11:46:25 -0700 Subject: [PATCH 0523/1981] feature: added C macro NGX_LUA_ABORT_AT_PANIC to allow generating a core dump when the Lua VM panics. --- src/ngx_http_lua_exception.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ngx_http_lua_exception.c b/src/ngx_http_lua_exception.c index 014aba444b..5f66086702 100644 --- a/src/ngx_http_lua_exception.c +++ b/src/ngx_http_lua_exception.c @@ -30,6 +30,9 @@ jmp_buf ngx_http_lua_exception; int ngx_http_lua_atpanic(lua_State *L) { +#if (NGX_LUA_ABORT_AT_PANIC) + abort(); +#else u_char *s = NULL; size_t len = 0; @@ -47,6 +50,7 @@ ngx_http_lua_atpanic(lua_State *L) /* restore nginx execution */ NGX_LUA_EXCEPTION_THROW(1); +#endif /* impossible to reach here */ } From ae2207bf8f186688218b5cd9a52131b7e9d1bbf2 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 3 May 2014 12:34:24 -0700 Subject: [PATCH 0524/1981] bumped version to 0.9.8. --- src/api/ngx_http_lua_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index a9a17a4f6d..43f78ca7db 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 9007 +#define ngx_http_lua_version 9008 typedef struct { From d8c45b872586cce6c960de549ea0ae50dc8407d9 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 3 May 2014 13:35:36 -0700 Subject: [PATCH 0525/1981] feature: make use of the new shm API in nginx 1.5.13+ to suppress the "no memory" error logging when the shared dicts run out of memory. --- src/ngx_http_lua_shdict.c | 4 ++++ t/043-shdict.t | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 16acf0d0e5..cf81195ffe 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -91,6 +91,10 @@ ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", &shm_zone->shm.name); +#if defined(nginx_version) && nginx_version >= 1005013 + ctx->shpool->log_nomem = 0; +#endif + done: dd("get lmcf"); diff --git a/t/043-shdict.t b/t/043-shdict.t index bc0e399b60..22ab0d8fed 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 15); +plan tests => repeat_each() * (blocks() * 3 + 17); #no_diff(); no_long_string(); @@ -401,10 +401,10 @@ GET /test --- response_body false no memory false --- log_level: info ---- error_log eval -qr/\[info\] .* ngx_slab_alloc\(\) failed: no memory in lua_shared_dict zone "dogs"/ --- no_error_log [error] +[crit] +ngx_slab_alloc() failed: no memory in lua_shared_dict zone @@ -706,10 +706,10 @@ GET /test --- response_body false no memory true --- log_level: info ---- error_log eval -qr/\[info\] .* ngx_slab_alloc\(\) failed: no memory in lua_shared_dict zone "dogs"/ --- no_error_log [error] +[crit] +ngx_slab_alloc() failed: no memory in lua_shared_dict zone From fa83bb5fdad53b7dc869bc38fc4df8e88bf7446f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 6 May 2014 13:15:30 -0700 Subject: [PATCH 0526/1981] added tests for exercising the memory fragmentation issue in nginx's built-in allocator for blocks larger than the page size this requires the following patch for the nginx core (1.7.0+): https://github.com/openresty/ngx_openresty/blob/master/patches/nginx-1.7.0-slab_defrag.patch --- t/126-shdict-frag.t | 1205 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1205 insertions(+) create mode 100644 t/126-shdict-frag.t diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t new file mode 100644 index 0000000000..2f414e0e64 --- /dev/null +++ b/t/126-shdict-frag.t @@ -0,0 +1,1205 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +#repeat_each(2); + +plan tests => repeat_each() * 36; + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: merge 2 single-page free blocks (forcibly evicted, merge forward) +--- http_config + lua_shared_dict dogs 20k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + for i = 1, 2 do + set_key("foo", string.rep("a", 4000)) + set_key("bar", string.rep("b", 4001)) + set_key("baz", string.rep("c", 8102)) + + check_key("foo") + check_key("bar") + check_key("baz") + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 4 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok +alloc pages: 1 NOT OK +free pages: 2 +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok + +--- response_body +successfully set foo. +successfully set bar. +successfully set baz with force. +foo not found +bar not found +found baz: 8102 +successfully set foo with force. +successfully set bar. +successfully set baz with force. +foo not found +bar not found +found baz: 8102 + +--- no_error_log +[error] + + + +=== TEST 2: merge 2 single-page free slabs (forcibly evicted, merge backward) +--- http_config + lua_shared_dict dogs 20k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + for i = 1, 2 do + set_key("foo", string.rep("a", 4000)) + set_key("bar", string.rep("b", 4001)) + check_key("foo") + set_key("baz", string.rep("c", 8102)) + + check_key("foo") + check_key("bar") + check_key("baz") + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 4 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok +alloc pages: 1 NOT OK +free pages: 2 +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok + +--- response_body +successfully set foo. +successfully set bar. +found foo: 4000 +successfully set baz with force. +foo not found +bar not found +found baz: 8102 +successfully set foo with force. +successfully set bar. +found foo: 4000 +successfully set baz with force. +foo not found +bar not found +found baz: 8102 + +--- no_error_log +[error] + + + +=== TEST 3: merge 3 single-page free slabs (actively deleted, merge backward AND forward) +--- http_config + lua_shared_dict dogs 25k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 2 do + set_key("foo", string.rep("a", 4000)) + set_key("bar", string.rep("b", 4001)) + set_key("baz", string.rep("c", 4002)) + + check_key("foo") + check_key("bar") + check_key("baz") + + dogs:delete("foo") + safe_set_key("blah", string.rep("a", 8100)) + dogs:delete("baz") + safe_set_key("blah", string.rep("a", 8100)) + dogs:delete("bar") + safe_set_key("blah", string.rep("a", 12010)) + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 5 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 3 ok +alloc pages: 1 NOT OK +free pages: 3 +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 3 ok + +--- response_body +successfully set foo. +successfully set bar. +successfully set baz. +found foo: 4000 +found bar: 4001 +found baz: 4002 +failed to safe set blah: no memory +failed to safe set blah: no memory +successfully safe set blah +successfully set foo with force. +successfully set bar. +successfully set baz. +found foo: 4000 +found bar: 4001 +found baz: 4002 +failed to safe set blah: no memory +failed to safe set blah: no memory +successfully safe set blah + +--- no_error_log +[error] + + + +=== TEST 4: merge one single-page block backward, but no more +--- http_config + lua_shared_dict dogs 25k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + set_key("foo", string.rep("a", 4000)) + set_key("bar", string.rep("b", 4001)) + set_key("baz", string.rep("c", 4002)) + + check_key("foo") + check_key("bar") + check_key("baz") + + dogs:delete("bar") + safe_set_key("blah", string.rep("a", 8100)) + dogs:delete("baz") + safe_set_key("blah", string.rep("a", 8100)) + check_key("foo") + dogs:delete("foo") + check_key("blah") + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 5 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok +free pages: 1 + +--- response_body +successfully set foo. +successfully set bar. +successfully set baz. +found foo: 4000 +found bar: 4001 +found baz: 4002 +failed to safe set blah: no memory +successfully safe set blah +found foo: 4000 +found blah: 8100 + +--- no_error_log +[error] + + + +=== TEST 5: merge one single-page block forward, but no more +--- http_config + lua_shared_dict dogs 25k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + set_key("foo", string.rep("a", 4000)) + set_key("bar", string.rep("b", 4001)) + set_key("baz", string.rep("c", 4002)) + + check_key("foo") + check_key("bar") + check_key("baz") + + dogs:delete("bar") + safe_set_key("blah", string.rep("a", 8100)) + dogs:delete("foo") + safe_set_key("blah", string.rep("a", 8100)) + check_key("baz") + dogs:delete("baz") + check_key("blah") + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 5 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok +free pages: 1 + +--- response_body +successfully set foo. +successfully set bar. +successfully set baz. +found foo: 4000 +found bar: 4001 +found baz: 4002 +failed to safe set blah: no memory +successfully safe set blah +found baz: 4002 +found blah: 8100 + +--- no_error_log +[error] + + + +=== TEST 6: merge 2 multi-page blocks (forcibly evicted, merge backward) +--- http_config + lua_shared_dict dogs 30k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + set_key("foo", string.rep("a", 8100)) + set_key("bar", string.rep("b", 8101)) + check_key("foo") + safe_set_key("baz", string.rep("c", 16300)) + dogs:delete("foo") + check_key("bar") + dogs:delete("bar") + safe_set_key("baz", string.rep("c", 16300)) + + check_key("foo") + check_key("bar") + check_key("baz") + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 6 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 2 ok +alloc pages: 2 ok +alloc pages: 4 NOT OK +free pages: 2 +free pages: 2 +alloc pages: 4 ok + +--- response_body +successfully set foo. +successfully set bar. +found foo: 8100 +failed to safe set baz: no memory +found bar: 8101 +successfully safe set baz +foo not found +bar not found +found baz: 16300 + +--- no_error_log +[error] + + + +=== TEST 7: merge big slabs (less than max slab size) backward +--- http_config + lua_shared_dict dogs 20k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + for j = 1, 50 do + dogs:set("foo" .. j, string.rep("a", 5)) + end + set_key("bar", string.rep("a", 4000)) + + for j = 1, 50 do + dogs:delete("foo" .. j) + end + + safe_set_key("baz", string.rep("b", 8100)) + check_key("bar") + + ngx.say("delete bar") + dogs:delete("bar") + + safe_set_key("baz", string.rep("b", 8100)) + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + //printf("slab max size: %d\n", @var("ngx_slab_max_size")) + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 4 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +free pages: 1 +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 ok + +--- response_body +successfully set bar. +failed to safe set baz: no memory +found bar: 4000 +delete bar +successfully safe set baz + +--- no_error_log +[error] + + + +=== TEST 8: cannot merge in-used big slabs page (backward) +--- http_config + lua_shared_dict dogs 20k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + for j = 1, 50 do + dogs:set("foo" .. j, string.rep("a", 5)) + end + set_key("bar", string.rep("a", 4000)) + + --[[ + for j = 1, 50 do + dogs:delete("foo" .. j) + end + ]] + + safe_set_key("baz", string.rep("b", 8100)) + check_key("bar") + + ngx.say("delete bar") + dogs:delete("bar") + + safe_set_key("baz", string.rep("b", 8100)) + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + //printf("slab max size: %d\n", @var("ngx_slab_max_size")) + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 4 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK + +--- response_body +successfully set bar. +failed to safe set baz: no memory +found bar: 4000 +delete bar +failed to safe set baz: no memory + +--- no_error_log +[error] + + + +=== TEST 8: cannot merge in-used big slabs page (forward) +--- http_config + lua_shared_dict dogs 20k; +--- config + location = /test { + content_by_lua ' + local dogs = ngx.shared.dogs + + local function check_key(key) + local res, err = dogs:get(key) + if res then + ngx.say("found ", key, ": ", #res) + else + if not err then + ngx.say(key, " not found") + else + ngx.say("failed to fetch key: ", err) + end + end + end + + local function set_key(key, value) + local ok, err, force = dogs:set(key, value) + if ok then + ngx.print("successfully set ", key) + if force then + ngx.say(" with force.") + else + ngx.say(".") + end + else + ngx.say("failed to set ", key, ": ", err) + end + end + + local function safe_set_key(key, value) + local ok, err = dogs:safe_set(key, value) + if ok then + ngx.say("successfully safe set ", key) + else + ngx.say("failed to safe set ", key, ": ", err) + end + end + + for i = 1, 1 do + set_key("bar", string.rep("a", 4000)) + for j = 1, 50 do + dogs:set("foo" .. j, string.rep("a", 5)) + end + + --[[ + for j = 1, 50 do + dogs:delete("foo" .. j) + end + ]] + + safe_set_key("baz", string.rep("b", 8100)) + check_key("bar") + + ngx.say("delete bar") + dogs:delete("bar") + + safe_set_key("baz", string.rep("b", 8100)) + end + '; + } +--- request +GET /test +--- stap +global first_time = 1 +global active = 1 + +F(ngx_http_lua_shdict_init_zone) { + active = 0 +} + +F(ngx_http_lua_shdict_init_zone).return { + active = 1 +} + +F(ngx_slab_alloc_pages) { + if (first_time) { + //printf("slab max size: %d\n", @var("ngx_slab_max_size")) + printf("total pages: %d\n", $pool->pages->slab) + first_time = 0 + } + if (active) { + printf("alloc pages: %d", $pages) + //print_ubacktrace() + } else { + printf("init zone alloc pages: %d", $pages) + } +} + +F(ngx_slab_alloc_pages).return { + if ($return) { + printf(" ok\n") + + } else { + printf(" NOT OK\n") + } +} + +F(ngx_slab_free_pages) { + printf("free pages: %d\n", $pages) +} + +--- stap_out +total pages: 4 +init zone alloc pages: 1 ok +init zone alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 1 ok +alloc pages: 2 NOT OK +free pages: 1 +alloc pages: 2 NOT OK + +--- response_body +successfully set bar. +failed to safe set baz: no memory +found bar: 4000 +delete bar +failed to safe set baz: no memory + +--- no_error_log +[error] + From 373376ce0f1318d31f0c6899b062bd334e6ad430 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 7 May 2014 15:58:55 -0700 Subject: [PATCH 0527/1981] try to make a test case for shdict fragmentation pass on i386. --- t/126-shdict-frag.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t index 2f414e0e64..bb035f62a1 100644 --- a/t/126-shdict-frag.t +++ b/t/126-shdict-frag.t @@ -992,7 +992,7 @@ successfully safe set baz end for i = 1, 1 do - for j = 1, 50 do + for j = 1, 63 do dogs:set("foo" .. j, string.rep("a", 5)) end set_key("bar", string.rep("a", 4000)) From f7443edc12b2b296ecc14bfc54a1fdf93d1e72e1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 8 May 2014 13:54:07 -0700 Subject: [PATCH 0528/1981] fixed the test index in 126-shdict-frag.t. --- t/126-shdict-frag.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t index bb035f62a1..7578ad71c6 100644 --- a/t/126-shdict-frag.t +++ b/t/126-shdict-frag.t @@ -1076,7 +1076,7 @@ failed to safe set baz: no memory -=== TEST 8: cannot merge in-used big slabs page (forward) +=== TEST 9: cannot merge in-used big slabs page (forward) --- http_config lua_shared_dict dogs 20k; --- config From ed1eb4f7fff24452adc7d07f5be318d820e79f1c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 8 May 2014 14:06:08 -0700 Subject: [PATCH 0529/1981] bugfix: the ngx.ctx table might be released prematurely when ngx.exit() was used to generate the response header. thanks Monkey Zhang for the report. now we release ngx.ctx in a request pool cleanup handler. --- src/ngx_http_lua_ctx.c | 73 ++++++++++++++++++++++++++++++++++++++++ src/ngx_http_lua_logby.c | 14 +------- src/ngx_http_lua_util.c | 44 ------------------------ t/033-ctx.t | 49 +++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 57 deletions(-) diff --git a/src/ngx_http_lua_ctx.c b/src/ngx_http_lua_ctx.c index 05a8cadab9..ac764147e0 100644 --- a/src/ngx_http_lua_ctx.c +++ b/src/ngx_http_lua_ctx.c @@ -14,6 +14,17 @@ #include "ngx_http_lua_ctx.h" +typedef struct { + int ref; + lua_State *vm; +} ngx_http_lua_ngx_ctx_cleanup_data_t; + + +static ngx_int_t ngx_http_lua_ngx_ctx_add_cleanup(ngx_http_request_t *r, + int ref); +static void ngx_http_lua_ngx_ctx_cleanup(void *data); + + int ngx_http_lua_ngx_get_ctx(lua_State *L) { @@ -39,6 +50,11 @@ ngx_http_lua_ngx_get_ctx(lua_State *L) lua_createtable(L, 0 /* narr */, 4 /* nrec */); lua_pushvalue(L, -1); ctx->ctx_ref = luaL_ref(L, -3); + + if (ngx_http_lua_ngx_ctx_add_cleanup(r, ctx->ctx_ref) != NGX_OK) { + return luaL_error(L, "no memory"); + } + return 1; } @@ -91,6 +107,11 @@ ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, lua_pushvalue(L, index); ctx->ctx_ref = luaL_ref(L, -2); lua_pop(L, 1); + + if (ngx_http_lua_ngx_ctx_add_cleanup(r, ctx->ctx_ref) != NGX_OK) { + return luaL_error(L, "no memory"); + } + return 0; } @@ -135,9 +156,61 @@ ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref) } ctx->ctx_ref = ref; + + if (ngx_http_lua_ngx_ctx_add_cleanup(r, ref) != NGX_OK) { + return NGX_ERROR; + } + return NGX_OK; } #endif /* NGX_HTTP_LUA_NO_FFI_API */ +static ngx_int_t +ngx_http_lua_ngx_ctx_add_cleanup(ngx_http_request_t *r, int ref) +{ + lua_State *L; + ngx_pool_cleanup_t *cln; + ngx_http_lua_ctx_t *ctx; + + ngx_http_lua_ngx_ctx_cleanup_data_t *data; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + L = ngx_http_lua_get_lua_vm(r, ctx); + + cln = ngx_pool_cleanup_add(r->pool, + sizeof(ngx_http_lua_ngx_ctx_cleanup_data_t)); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_http_lua_ngx_ctx_cleanup; + + data = cln->data; + data->vm = L; + data->ref = ref; + + return NGX_OK; +} + + +static void +ngx_http_lua_ngx_ctx_cleanup(void *data) +{ + lua_State *L; + + ngx_http_lua_ngx_ctx_cleanup_data_t *clndata = data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua release ngx.ctx at ref %d", clndata->ref); + + L = clndata->vm; + + lua_pushliteral(L, ngx_http_lua_ctx_tables_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, clndata->ref); + lua_pop(L, 1); +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 2960cbea64..9ebbfe693f 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -68,8 +68,6 @@ ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; - ngx_int_t rc; - lua_State *L; ngx_http_lua_ctx_t *ctx; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -97,17 +95,7 @@ ngx_http_lua_log_handler(ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; dd("calling log handler"); - rc = llcf->log_handler(r); - - /* we must release the ngx.ctx table here because request cleanup runs - * before log phase handlers */ - - if (ctx->ctx_ref != LUA_NOREF) { - L = ngx_http_lua_get_lua_vm(r, ctx); - ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); - } - - return rc; + return llcf->log_handler(r); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0a5823bd42..336564cd81 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -968,8 +968,6 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) lua_State *L; ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_ctx_t *cur_ctx; r = ctx->request; @@ -998,53 +996,11 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) L = ngx_http_lua_get_lua_vm(r, ctx); - /* we cannot release the ngx.ctx table if we have log_by_lua* hooks - * because request cleanup runs before log phase handlers */ - - if (ctx->ctx_ref != LUA_NOREF) { - - if (forcible || r->connection->fd == -1 /* being a fake request */) { - ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); - - } else { - - cur_ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (cur_ctx != ctx) { - /* internal redirects happened */ - ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); - - } else { - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->log_handler == NULL) { - /* no log_by_lua* configured */ - ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, - ctx); - } - } - } - } - ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_del_all_threads(r, L, ctx); } -void -ngx_http_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L, - ngx_http_lua_ctx_t *ctx) -{ - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "lua release ngx.ctx at ref %d", ctx->ctx_ref); - - lua_pushliteral(L, ngx_http_lua_ctx_tables_key); - lua_rawget(L, LUA_REGISTRYINDEX); - luaL_unref(L, -1, ctx->ctx_ref); - ctx->ctx_ref = LUA_NOREF; - lua_pop(L, 1); -} - - /* * description: * run a Lua coroutine specified by ctx->cur_co_ctx->co diff --git a/t/033-ctx.t b/t/033-ctx.t index 2e056567ae..e9b972bfac 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -390,3 +390,52 @@ foo --- error_log lua release ngx.ctx at ref + + +=== TEST 17: ngx.ctx gets prematurely released ngx.exit() +--- config + location = /t { + rewrite_by_lua ' + ngx.ctx.foo = 3 + '; + content_by_lua ' + -- if ngx.headers_sent ~= true then ngx.send_headers() end + return ngx.exit(200) + '; + header_filter_by_lua ' + if ngx.ctx.foo ~= 3 then + ngx.log(ngx.ERR, "bad ngx.ctx.foo: ", ngx.ctx.foo) + end + '; + } +--- request + GET /t +--- response_body +--- no_error_log +[error] + + + +=== TEST 18: ngx.ctx gets prematurely released ngx.exit() (lua_code_cache off) +--- config + location = /t { + lua_code_cache off; + rewrite_by_lua ' + ngx.ctx.foo = 3 + '; + content_by_lua ' + -- if ngx.headers_sent ~= true then ngx.send_headers() end + return ngx.exit(200) + '; + header_filter_by_lua ' + if ngx.ctx.foo ~= 3 then + ngx.log(ngx.ERR, "bad ngx.ctx.foo: ", ngx.ctx.foo) + end + '; + } +--- request + GET /t +--- response_body +--- no_error_log +[error] + From 509bb9819e1ca8d183e7abfbe51fa6b6c4b16e1e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 8 May 2014 14:07:06 -0700 Subject: [PATCH 0530/1981] removed an obsolete code comment. --- src/ngx_http_lua_util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 336564cd81..4c87101afd 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -3610,7 +3610,6 @@ ngx_http_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, ngx_http_lua_preload_hook_t *hook; ngx_http_lua_vm_state_t *state; - /* add new cleanup handler to config mem pool */ cln = ngx_pool_cleanup_add(pool, 0); if (cln == NULL) { return NULL; From b57d60d4c9db29bb9ad5961f363af52acf754aa0 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 8 May 2014 16:37:23 -0700 Subject: [PATCH 0531/1981] bugfix: we did not call our coroutine cleanup handlers right after our coroutine completes (either successfully or unsuccessfully) otherwise segmentation fault might happen when the Lua VM throws out unexpected exceptions like "attempt to yield across C-call boundary". thanks Lipin Dmitriy for the report in #361. --- src/ngx_http_lua_util.c | 12 +++++++++ t/077-sleep.t | 54 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 4c87101afd..538050b163 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1196,6 +1196,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, case 0: + if (ctx->cur_co_ctx->cleanup) { + ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx); + ctx->cur_co_ctx->cleanup = NULL; + } + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; @@ -1353,6 +1358,13 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, msg = "unknown reason"; } +#if 1 + if (ctx->cur_co_ctx->cleanup) { + ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx); + ctx->cur_co_ctx->cleanup = NULL; + } +#endif + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 0); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; diff --git a/t/077-sleep.t b/t/077-sleep.t index 7846971a88..15030d53eb 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 43; +plan tests => repeat_each() * 51; #no_diff(); #no_long_string(); @@ -254,3 +254,55 @@ hello --- error_log API disabled in the context of log_by_lua* + + +=== TEST 11: ngx.sleep() fails to yield (xpcall err handler) +--- config + location = /t { + content_by_lua ' + local function f() + return error(1) + end + local function err() + ngx.sleep(0.001) + end + xpcall(f, err) + ngx.say("ok") + '; + } +--- request + GET /t +--- response_body +ok +--- error_log +lua clean up the timer for pending ngx.sleep +--- no_error_log +[error] + + + +=== TEST 12: ngx.sleep() fails to yield (require) +--- http_config + lua_package_path "$prefix/html/?.lua;;"; +--- config + location = /t { + content_by_lua ' + package.loaded["foosleep"] = nil + require "foosleep"; + '; + } +--- request + GET /t +--- user_files +>>> foosleep.lua +ngx.sleep(0.001) + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- wait: 0.2 +--- error_log eval +[ +"lua clean up the timer for pending ngx.sleep", +qr{runtime error: attempt to yield across (?:metamethod/)?C-call boundary}, +] + From 5d614b0945eec0be222ce88fd097d1d066d7bd94 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 9 May 2014 14:54:18 -0700 Subject: [PATCH 0532/1981] added a (passing) fuzz test case for shdict. --- t/126-shdict-frag.t | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t index 7578ad71c6..db4790d7e6 100644 --- a/t/126-shdict-frag.t +++ b/t/126-shdict-frag.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; #repeat_each(2); -plan tests => repeat_each() * 36; +plan tests => repeat_each() * 39; #no_diff(); no_long_string(); @@ -1203,3 +1203,46 @@ failed to safe set baz: no memory --- no_error_log [error] + + +=== TEST 10: fuzz testing +--- http_config + lua_shared_dict dogs 200k; +--- config + location = /t { + content_by_lua ' + local rand = math.random + local dogs = ngx.shared.dogs + local maxsz = 9000 + local maxkeyidx = 30 + local rep = string.rep + + math.randomseed(ngx.time()) + for i = 1, 30000 do + local key = "mylittlekey" .. rand(maxkeyidx) + local ok, err = dogs:get(key) + if not ok or rand() > 0.6 then + sz = rand(maxsz) + val = rep("a", sz) + local ok, err, forcible = dogs:set(key, val) + if err then + ngx.log(ngx.ERR, "failed to set key: ", err) + -- return + end + if forcible then + -- error("forcible") + end + end + end + ngx.say("ok") + '; + } +--- request +GET /t +--- response_body +ok + +--- no_error_log +[error] +--- timeout: 30 + From 3b3239c229504683fe47c8c62060e641ce5d451e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 10 May 2014 10:03:36 -0700 Subject: [PATCH 0533/1981] added (passing) tests for yielding failures in cosocket DNS resolving. --- t/058-tcp-socket.t | 72 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index c61fd170c6..a9c59e2e86 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 150; +plan tests => repeat_each() * 160; our $HtmlDir = html_dir; @@ -3003,3 +3003,73 @@ runtime error: content_by_lua:16: bad request --- no_error_log [alert] + + +=== TEST 50: cosocket resolving aborted by coroutine yielding failures (require) +--- http_config + lua_package_path "$prefix/html/?.lua;;"; + resolver 8.8.8.8; + +--- config + location = /t { + content_by_lua ' + package.loaded.myfoo = nil + require "myfoo" + '; + } +--- request + GET /t +--- user_files +>>> myfoo.lua +local sock = ngx.socket.tcp() +local ok, err = sock:connect("agentzh.org") +if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return +end + +--- response_body_like: 500 Internal Server Error +--- wait: 0.3 +--- error_code: 500 +--- error_log +resolve name done +runtime error: attempt to yield across C-call boundary +--- no_error_log +[alert] + + + +=== TEST 51: cosocket resolving aborted by coroutine yielding failures (xpcall err) +--- http_config + lua_package_path "$prefix/html/?.lua;;"; + resolver 8.8.8.8; + +--- config + location = /t { + content_by_lua ' + local function f() + return error(1) + end + local function err() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("agentzh.org") + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + end + xpcall(f, err) + ngx.say("ok") + '; + } +--- request + GET /t +--- response_body +ok +--- wait: 0.3 +--- error_log +resolve name done +--- no_error_log +[error] +[alert] + From af2d3570bfd25d3d35da13a87985c0bd0dae4e04 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 10 May 2014 11:02:37 -0700 Subject: [PATCH 0534/1981] added a (passing) fuzz testing for aborting many pending timers. --- t/109-timer-hup.t | 65 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 0982cb03af..2bb6ee1414 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -28,7 +28,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * 76; +plan tests => repeat_each() * 81; #no_diff(); no_long_string(); @@ -439,3 +439,66 @@ failed to register a new timer after reload --- grep_error_log_out lua found 1 pending timers + + +=== TEST 6: HUP reload should abort pending timers (fuzz test) +--- http_config + lua_max_pending_timers 8192; + +--- config + location /t { + content_by_lua ' + local job = function(premature, kill) + if premature then + return + end + + if kill then + local f, err = io.open("t/servroot/logs/nginx.pid", "r") + if not f then + ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) + return + end + local pid = f:read() + -- ngx.say("master pid: [", pid, "]") + f:close() + + os.execute("kill -HUP " .. pid) + end + end + + math.randomseed(ngx.time()) + local rand = math.random + local newtimer = ngx.timer.at + for i = 1, 8191 do + local delay = rand(4096) + local ok, err = newtimer(delay, job, false) + if not ok then + ngx.say("failed to create timer at ", delay, ": ", err) + return + end + end + local ok, err = newtimer(0, job, true) + if not ok then + ngx.say("failed to create the killer timer: ", err) + return + end + ngx.say("ok") + '; + } +--- request +GET /t + +--- response_body +ok + +--- wait: 0.3 +--- no_error_log +[error] +[alert] + +--- grep_error_log eval: qr/lua found \d+ pending timers/ +--- grep_error_log_out +lua found 8191 pending timers +--- timeout: 20 + From a2dee0c62648c22060bc51a9fab440c4e84f717a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 10 May 2014 11:06:41 -0700 Subject: [PATCH 0535/1981] added more code comments to the timer implementation. --- src/ngx_http_lua_timer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 861261f280..120c5286b6 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -487,6 +487,8 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) prev, cur, cur->parent, cur->left, cur->right); if (prev == cur->parent) { + /* neither of the children has been accessed yet */ + next = cur->left; if (next == sentinel) { ev = (ngx_event_t *) @@ -501,6 +503,8 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) } } else if (prev == cur->left) { + /* just accessed the left child */ + ev = (ngx_event_t *) ((char *) cur - offsetof(ngx_event_t, timer)); @@ -512,9 +516,11 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) next = (cur->right != sentinel) ? cur->right : cur->parent; } else if (prev == cur->right) { + /* already accessed both children */ next = cur->parent; } else { + /* not reacheable */ next = NULL; } From 0f68763de5856de51a0f024abb49a740b0102cf5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 10 May 2014 11:25:01 -0700 Subject: [PATCH 0536/1981] bugfix: nginx does not guarentee the parent pointer of the rbtree root is meaningful, which could lead to inifinite loops when ngx_lua tried to abort pending timers prematurely (upon worker exit). thanks pengqi for the patch in #362. --- src/ngx_http_lua_timer.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 120c5286b6..8c496ee024 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -419,7 +419,7 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) ngx_int_t i, n; ngx_event_t **events; ngx_connection_t *c, *saved_c = NULL; - ngx_rbtree_node_t *cur, *prev, *next, *sentinel; + ngx_rbtree_node_t *cur, *prev, *next, *sentinel, *temp; ngx_http_lua_timer_ctx_t *tctx; ngx_http_lua_main_conf_t *lmcf; @@ -463,7 +463,13 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) sentinel = ngx_event_timer_rbtree.sentinel; cur = ngx_event_timer_rbtree.root; - prev = cur->parent; + + /* XXX nginx does not guarentee the parent of root is meaningful, + * so we temporarily override it to simplify tree traversal. */ + temp = cur->parent; + cur->parent = NULL; + + prev = NULL; events = ngx_pcalloc(ngx_cycle->pool, lmcf->pending_timers * sizeof(ngx_event_t)); @@ -528,6 +534,9 @@ ngx_http_lua_abort_pending_timers(ngx_event_t *ev) cur = next; } + /* restore the old tree root's parent */ + ngx_event_timer_rbtree.root->parent = temp; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua found %i pending timers to be aborted prematurely", n); From eb4f986764c2529a21325b0f053abf1aad930f52 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 11 May 2014 19:46:16 -0700 Subject: [PATCH 0537/1981] 126-shdict-frag.t: increased the timeout threshold. --- t/126-shdict-frag.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t index db4790d7e6..c2975a4f4c 100644 --- a/t/126-shdict-frag.t +++ b/t/126-shdict-frag.t @@ -1244,5 +1244,5 @@ ok --- no_error_log [error] ---- timeout: 30 +--- timeout: 60 From a43bca8d107ec46e288d64f3c36e959673841ea7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 11 May 2014 19:48:24 -0700 Subject: [PATCH 0538/1981] fixed the wait time for slow testing mode. --- t/023-rewrite/on-abort.t | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index a799038812..f971f6ca22 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -366,7 +366,7 @@ delete thread 1 --- timeout: 0.2 --- abort ---- wait: 0.4 +--- wait: 0.5 --- ignore_response --- no_error_log [error] @@ -602,6 +602,7 @@ terminate 4: ok delete thread 4 lua req cleanup +--- wait: 0.5 --- response_body done --- no_error_log From 0a845986a37c3a2d9cdbe02a7a77a1498c53622b Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 11 May 2014 20:00:09 -0700 Subject: [PATCH 0539/1981] 126-shdict-frag.t: force a full GC cycle at the end of the Lua handler to help the "check leaks" testing mode. --- t/126-shdict-frag.t | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/t/126-shdict-frag.t b/t/126-shdict-frag.t index c2975a4f4c..8c1ad758fe 100644 --- a/t/126-shdict-frag.t +++ b/t/126-shdict-frag.t @@ -63,6 +63,8 @@ __DATA__ check_key("bar") check_key("baz") end + + collectgarbage() '; } --- request @@ -190,6 +192,8 @@ found baz: 8102 check_key("bar") check_key("baz") end + + collectgarbage() '; } --- request @@ -334,6 +338,8 @@ found baz: 8102 dogs:delete("bar") safe_set_key("blah", string.rep("a", 12010)) end + + collectgarbage() '; } --- request @@ -487,6 +493,8 @@ successfully safe set blah dogs:delete("foo") check_key("blah") end + + collectgarbage() '; } --- request @@ -620,6 +628,8 @@ found blah: 8100 dogs:delete("baz") check_key("blah") end + + collectgarbage() '; } --- request @@ -750,6 +760,8 @@ found blah: 8100 check_key("bar") check_key("baz") end + + collectgarbage() '; } --- request @@ -881,6 +893,8 @@ found baz: 16300 safe_set_key("baz", string.rep("b", 8100)) end + + collectgarbage() '; } --- request @@ -1011,6 +1025,8 @@ successfully safe set baz safe_set_key("baz", string.rep("b", 8100)) end + + collectgarbage() '; } --- request @@ -1140,6 +1156,8 @@ failed to safe set baz: no memory safe_set_key("baz", string.rep("b", 8100)) end + + collectgarbage() '; } --- request @@ -1235,6 +1253,7 @@ failed to safe set baz: no memory end end ngx.say("ok") + collectgarbage() '; } --- request From 0a11b402aa192611f5d6ca56fd22f8f0020e0cb7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 11 May 2014 21:25:26 -0700 Subject: [PATCH 0540/1981] feature: added pure C API function, ngx_http_lua_ffi_ngx_now, for FFI-based implementation for ngx.now() like lua-resty-core. --- src/ngx_http_lua_time.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index d256870ecd..8d0e368e13 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -247,4 +247,18 @@ ngx_http_lua_inject_req_time_api(lua_State *L) lua_setfield(L, -2, "start_time"); } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +double +ngx_http_lua_ffi_ngx_now(void) +{ + ngx_time_t *tp; + + tp = ngx_timeofday(); + + return tp->sec + tp->msec / 1000.0; +} +#endif /* NGX_HTTP_LUA_NO_FFI_API */ + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From c178302bd10fcd17d76df7518e975929a7a44cb2 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 12 May 2014 12:54:40 -0700 Subject: [PATCH 0541/1981] updated the test index in 109-timer-hup.t. --- t/109-timer-hup.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/109-timer-hup.t b/t/109-timer-hup.t index 2bb6ee1414..0327d4e35c 100644 --- a/t/109-timer-hup.t +++ b/t/109-timer-hup.t @@ -441,7 +441,7 @@ lua found 1 pending timers -=== TEST 6: HUP reload should abort pending timers (fuzz test) +=== TEST 7: HUP reload should abort pending timers (fuzz test) --- http_config lua_max_pending_timers 8192; From cae72592808ac7d1d3c3b2907a7dc2e5dbc20700 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Mon, 12 May 2014 13:41:57 -0700 Subject: [PATCH 0542/1981] added a fix for the leftover cases in commit b57d60d4c9d we did not call leftover coctx cleanup handlers for ngx.exit(), ngx.exect(), and ngx.req.set_uri(uri, true). thanks Lipin Dmitriy for the new report in #361. --- src/ngx_http_lua_util.c | 15 ++++++ t/077-sleep.t | 102 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 538050b163..a5cb56416a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2144,6 +2144,11 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, "lua thread initiated internal redirect to %V", &ctx->exec_uri); + if (ctx->cur_co_ctx->cleanup) { + ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx); + ctx->cur_co_ctx->cleanup = NULL; + } + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; @@ -2249,6 +2254,11 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, } #endif + if (ctx->cur_co_ctx->cleanup) { + ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx); + ctx->cur_co_ctx->cleanup = NULL; + } + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; @@ -2587,6 +2597,11 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, "lua thread aborting request with URI rewrite jump: " "\"%V?%V\"", &r->uri, &r->args); + if (ctx->cur_co_ctx->cleanup) { + ctx->cur_co_ctx->cleanup(ctx->cur_co_ctx); + ctx->cur_co_ctx->cleanup = NULL; + } + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; diff --git a/t/077-sleep.t b/t/077-sleep.t index 15030d53eb..c4d7c0cafc 100644 --- a/t/077-sleep.t +++ b/t/077-sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 51; +plan tests => repeat_each() * 63; #no_diff(); #no_long_string(); @@ -306,3 +306,103 @@ ngx.sleep(0.001) qr{runtime error: attempt to yield across (?:metamethod/)?C-call boundary}, ] + + +=== TEST 13: sleep coctx handler did not get called in ngx.exit(). +--- config + location /t { + content_by_lua " + local function sleep(t) + --- nginx return reply to client without waiting + ngx.sleep(t) + end + + local function wait() + --- worker would crash afterwards + xpcall(function () error(1) end, function() return sleep(0.001) end) + --- ngx.exit was required to crash worker + ngx.exit(200) + end + + wait() + "; + } +--- request + GET /t + +--- wait: 0.1 +--- response_body +--- no_error_log +[error] +[alert] + + + +=== TEST 14: sleep coctx handler did not get called in ngx.exec(). +--- config + location /t { + content_by_lua ' + local function sleep(t) + --- nginx return reply to client without waiting + ngx.sleep(t) + end + + local function wait() + --- worker would crash afterwards + xpcall(function () error(1) end, function() return sleep(0.001) end) + --- ngx.exit was required to crash worker + ngx.exec("/dummy") + end + + wait() + '; + } + + location /dummy { + echo ok; + } +--- request + GET /t + +--- wait: 0.1 +--- response_body +ok +--- no_error_log +[error] +[alert] + + + +=== TEST 15: sleep coctx handler did not get called in ngx.req.set_uri(uri, true). +--- config + location /t { + rewrite_by_lua ' + local function sleep(t) + --- nginx return reply to client without waiting + ngx.sleep(t) + end + + local function wait() + --- worker would crash afterwards + xpcall(function () error(1) end, function() return sleep(0.001) end) + --- ngx.exit was required to crash worker + ngx.req.set_uri("/dummy", true) + end + + wait() + '; + } + + location /dummy { + echo ok; + } +--- request + GET /t + +--- wait: 0.1 +--- response_body +ok +--- no_error_log +[error] +[alert] + From fb5f9754180c0ebcc4bd5347a4909e04e04f1713 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 14 May 2014 11:48:13 -0700 Subject: [PATCH 0543/1981] feature: attempt to allow use of 3rd-party pcre bindings in init_by_lua*. thanks ikokostya for the feature request in #368. --- src/ngx_http_lua_util.c | 7 ++++++- t/034-match.t | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a5cb56416a..facb55c24e 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -3952,12 +3952,17 @@ ngx_http_lua_report(ngx_log_t *log, lua_State *L, int status, int ngx_http_lua_do_call(ngx_log_t *log, lua_State *L) { - int status, base; + int status, base; + ngx_pool_t *old_pool; base = lua_gettop(L); /* function index */ lua_pushcfunction(L, ngx_http_lua_traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ + + old_pool = ngx_http_lua_pcre_malloc_init(ngx_cycle->pool); status = lua_pcall(L, 0, 0, base); + ngx_http_lua_pcre_malloc_done(old_pool); + lua_remove(L, base); return status; diff --git a/t/034-match.t b/t/034-match.t index ba4bcc572c..172c1b3cda 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -1125,3 +1125,26 @@ failed to match 2: m size: 2 2: res size: 2 + + +=== TEST 48: init_by_lua +--- http_config + init_by_lua ' + m = ngx.re.match("hello, 1234", "(\\\\d+)") + '; +--- config + location /re { + content_by_lua ' + if m then + ngx.say(m[0]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 +--- SKIP + From 7f184ec4c1ec7f9c114c1974d6405c0f726158b1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 18 May 2014 15:36:21 -0700 Subject: [PATCH 0544/1981] feature: now we save the original pattern string pointer value into our ngx_http_lua_regex_t struct, to help runtime regex profiling and debugging. --- src/ngx_http_lua_regex.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 06e2d219ac..a66b06c4f7 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -58,6 +58,11 @@ typedef struct { pcre_extra *regex_sd; ngx_http_lua_complex_value_t *replace; + +#ifndef NGX_HTTP_LUA_NO_FFI_API + /* only for (stap) debugging, and may be an invalid pointer */ + const u_char *pattern; +#endif } ngx_http_lua_regex_t; @@ -2230,6 +2235,10 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, re->captures = cap; re->replace = NULL; + /* only for (stap) debugging, the pointer might be invalid when the string is + * collected later on.... */ + re->pattern = pat; + return re; error: From b438f972d5a676445b0b2f6dfd832cab6100546c Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sun, 18 May 2014 15:36:21 -0700 Subject: [PATCH 0545/1981] feature: now we save the original pattern string pointer value into our ngx_http_lua_regex_t struct, to help runtime regex profiling and debugging. --- src/ngx_http_lua_regex.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 06e2d219ac..a66b06c4f7 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -58,6 +58,11 @@ typedef struct { pcre_extra *regex_sd; ngx_http_lua_complex_value_t *replace; + +#ifndef NGX_HTTP_LUA_NO_FFI_API + /* only for (stap) debugging, and may be an invalid pointer */ + const u_char *pattern; +#endif } ngx_http_lua_regex_t; @@ -2230,6 +2235,10 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, re->captures = cap; re->replace = NULL; + /* only for (stap) debugging, the pointer might be invalid when the string is + * collected later on.... */ + re->pattern = pat; + return re; error: From c478f41e1b8edcd3ddcd469fd58efebcede8369a Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 20 May 2014 16:03:39 -0700 Subject: [PATCH 0546/1981] change: access_by_lua* will now terminate the current request if the response header has already been sent (via calls like ngx.say and ngx.send_headers) at that point (otherwise nginx might crash when other modules try to generate their own response). thanks yaronli and Sophos for the report in #364. --- src/ngx_http_lua_accessby.c | 69 ++++++++++++++++++++++++++++++++----- t/024-access/mixed.t | 49 +++++++++++++++----------- t/024-access/sanity.t | 47 ++++++++++++++++++++++++- t/027-multi-capture.t | 41 +++++++++++++--------- t/033-ctx.t | 9 +++-- 5 files changed, 165 insertions(+), 50 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index ca79ea3457..8c2edc4b9d 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -100,10 +100,34 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } + if (rc == NGX_OK) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in access_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + return NGX_OK; + } + return NGX_DECLINED; } @@ -283,7 +307,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) dd("returned %d", (int) rc); - if (rc == NGX_ERROR || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } @@ -292,25 +316,54 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } - return NGX_DECLINED; - } + if (rc != NGX_OK) { + return NGX_DECLINED; + } - if (rc == NGX_DONE) { + } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } - return NGX_DECLINED; + if (rc != NGX_OK) { + return NGX_DECLINED; + } } +#if 1 + if (rc == NGX_OK) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in access_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + return NGX_OK; + } +#endif + return NGX_DECLINED; } diff --git a/t/024-access/mixed.t b/t/024-access/mixed.t index 3efec3443d..1644c6c394 100644 --- a/t/024-access/mixed.t +++ b/t/024-access/mixed.t @@ -9,12 +9,12 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -37,15 +37,14 @@ __DATA__ ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("access GET: " .. res.status); + print("access GET: ", res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("access PUT: " .. res.status); + print("access PUT: ", res.status); res = ngx.location.capture("/memc"); - ngx.say("access cached: " .. res.body); - + print("access cached: ", res.body); '; content_by_lua ' @@ -60,18 +59,24 @@ __DATA__ res = ngx.location.capture("/memc"); ngx.say("content cached: " .. res.body); - '; } --- request GET /lua --- response_body -access GET: 404 -access PUT: 201 -access cached: hello content GET: 404 content PUT: 201 content cached: hello +--- grep_error_log eval: qr/access .+?(?= while )/ +--- grep_error_log_out +access GET: 404 +access PUT: 201 +access cached: hello + +--- log_level: info +--- no_error_log +[error] +[alert] @@ -184,30 +189,28 @@ world\x03\x04\xff ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("rewrite GET: " .. res.status); + print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("rewrite PUT: " .. res.status); + print("rewrite PUT: " .. res.status); res = ngx.location.capture("/memc"); - ngx.say("rewrite cached: " .. res.body); - + print("rewrite cached: " .. res.body); '; access_by_lua ' ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("access GET: " .. res.status); + print("access GET: " .. res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("access PUT: " .. res.status); + print("access PUT: " .. res.status); res = ngx.location.capture("/memc"); - ngx.say("access cached: " .. res.body); - + print("access cached: " .. res.body); '; content_by_lua ' @@ -228,14 +231,18 @@ world\x03\x04\xff --- request GET /lua --- response_body +content GET: 404 +content PUT: 201 +content cached: hello + +--- grep_error_log eval: qr/(?:rewrite|access) .+?(?= while )/ +--- grep_error_log_out rewrite GET: 404 rewrite PUT: 201 rewrite cached: hello access GET: 404 access PUT: 201 access cached: hello -content GET: 404 -content PUT: 201 -content cached: hello +--- log_level: info diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 51baeee65e..fc167613c0 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 11); #no_diff(); no_long_string(); @@ -698,3 +698,48 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ + + +=== TEST 37: use of ngx.say() in access_by_lua without exiting with 200+. +--- config + location /t { + access_by_lua "ngx.say('test')"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + + + +=== TEST 38: use of ngx.say() in access_by_lua without exiting with 200+. (with explicit ngx.eof()) +--- config + location /t { + access_by_lua "ngx.say('test') ngx.eof()"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + + + +=== TEST 39: use of ngx.say() in access_by_lua without exiting with 200+. (with IO) +--- config + location /t { + access_by_lua "ngx.say('test') ngx.sleep(0.001)"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index 654c6d5e0e..06873c1c4c 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(10); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 4); #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -543,21 +543,21 @@ res4.body = f location /main { rewrite_by_lua ' local res = ngx.location.capture("/a") - ngx.say("rewrite a: " .. res.body) + print("rewrite a: " .. res.body) res = ngx.location.capture("/b") - ngx.say("rewrite b: " .. res.body) + print("rewrite b: " .. res.body) res = ngx.location.capture("/c") - ngx.say("rewrite c: " .. res.body) + print("rewrite c: " .. res.body) '; access_by_lua ' local res = ngx.location.capture("/A") - ngx.say("access A: " .. res.body) + print("access A: " .. res.body) res = ngx.location.capture("/B") - ngx.say("access B: " .. res.body) + print("access B: " .. res.body) '; content_by_lua ' @@ -594,14 +594,18 @@ res4.body = f --- request GET /main --- response_body +content d: d +content e: e +content f: f + +--- log_level: info +--- grep_error_log eval: qr/rewrite .+?(?= while )|access .+?(?=,)/ +--- grep_error_log_out rewrite a: a rewrite b: b rewrite c: c access A: A access B: B -content d: d -content e: e -content f: f @@ -612,17 +616,17 @@ content f: f local a, b, c = ngx.location.capture_multi{ {"/a"}, {"/b"}, {"/c"}, } - ngx.say("rewrite a: " .. a.body) - ngx.say("rewrite b: " .. b.body) - ngx.say("rewrite c: " .. c.body) + print("rewrite a: " .. a.body) + print("rewrite b: " .. b.body) + print("rewrite c: " .. c.body) '; access_by_lua ' local A, B = ngx.location.capture_multi{ {"/A"}, {"/B"}, } - ngx.say("access A: " .. A.body) - ngx.say("access B: " .. B.body) + print("access A: " .. A.body) + print("access B: " .. B.body) '; content_by_lua ' @@ -703,14 +707,17 @@ F(ngx_http_lua_handle_subreq_responses) { } --- response_body +content d: d +content e: e +content f: f +--- log_level: info +--- grep_error_log eval: qr/rewrite .+?(?= while )|access .+?(?=,)/ +--- grep_error_log_out rewrite a: a rewrite b: b rewrite c: c access A: A access B: B -content d: d -content e: e -content f: f diff --git a/t/033-ctx.t b/t/033-ctx.t index e9b972bfac..8301bacc01 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 7); +plan tests => repeat_each() * (blocks() * 3 + 8); #no_diff(); #no_long_string(); @@ -39,7 +39,7 @@ GET /lua --- config location /lua { rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) + print("foo = ", ngx.ctx.foo) ngx.ctx.foo = 76 '; access_by_lua ' @@ -52,10 +52,13 @@ GET /lua --- request GET /lua --- response_body -foo = nil 79 --- no_error_log [error] +--- grep_error_log eval: qr/foo = [^,]+/ +--- log_level: info +--- grep_error_log_out +foo = nil From a1ea105f4cacceddba051065bfef6572be95cef1 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 20 May 2014 16:03:39 -0700 Subject: [PATCH 0547/1981] change: access_by_lua* will now terminate the current request if the response header has already been sent (via calls like ngx.say and ngx.send_headers) at that point (otherwise nginx might crash when other modules try to generate their own response). thanks yaronli and Sophos for the report in #364. --- src/ngx_http_lua_accessby.c | 69 ++++++++++++++++++++++++++++++++----- t/024-access/mixed.t | 49 +++++++++++++++----------- t/024-access/sanity.t | 47 ++++++++++++++++++++++++- t/027-multi-capture.t | 41 +++++++++++++--------- t/033-ctx.t | 9 +++-- 5 files changed, 165 insertions(+), 50 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index ca79ea3457..8c2edc4b9d 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -100,10 +100,34 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } + if (rc == NGX_OK) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in access_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + return NGX_OK; + } + return NGX_DECLINED; } @@ -283,7 +307,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) dd("returned %d", (int) rc); - if (rc == NGX_ERROR || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } @@ -292,25 +316,54 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } - return NGX_DECLINED; - } + if (rc != NGX_OK) { + return NGX_DECLINED; + } - if (rc == NGX_DONE) { + } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); - if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; } - return NGX_DECLINED; + if (rc != NGX_OK) { + return NGX_DECLINED; + } } +#if 1 + if (rc == NGX_OK) { + if (r->header_sent) { + dd("header already sent"); + + /* response header was already generated in access_by_lua*, + * so it is no longer safe to proceed to later phases + * which may generate responses again */ + + if (!ctx->eof) { + dd("eof not yet sent"); + + rc = ngx_http_lua_send_chain_link(r, ctx, NULL + /* indicate last_buf */); + if (rc == NGX_ERROR || rc > NGX_OK) { + return rc; + } + } + + return NGX_HTTP_OK; + } + + return NGX_OK; + } +#endif + return NGX_DECLINED; } diff --git a/t/024-access/mixed.t b/t/024-access/mixed.t index 3efec3443d..1644c6c394 100644 --- a/t/024-access/mixed.t +++ b/t/024-access/mixed.t @@ -9,12 +9,12 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 4); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -37,15 +37,14 @@ __DATA__ ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("access GET: " .. res.status); + print("access GET: ", res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("access PUT: " .. res.status); + print("access PUT: ", res.status); res = ngx.location.capture("/memc"); - ngx.say("access cached: " .. res.body); - + print("access cached: ", res.body); '; content_by_lua ' @@ -60,18 +59,24 @@ __DATA__ res = ngx.location.capture("/memc"); ngx.say("content cached: " .. res.body); - '; } --- request GET /lua --- response_body -access GET: 404 -access PUT: 201 -access cached: hello content GET: 404 content PUT: 201 content cached: hello +--- grep_error_log eval: qr/access .+?(?= while )/ +--- grep_error_log_out +access GET: 404 +access PUT: 201 +access cached: hello + +--- log_level: info +--- no_error_log +[error] +[alert] @@ -184,30 +189,28 @@ world\x03\x04\xff ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("rewrite GET: " .. res.status); + print("rewrite GET: " .. res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("rewrite PUT: " .. res.status); + print("rewrite PUT: " .. res.status); res = ngx.location.capture("/memc"); - ngx.say("rewrite cached: " .. res.body); - + print("rewrite cached: " .. res.body); '; access_by_lua ' ngx.location.capture("/flush"); res = ngx.location.capture("/memc"); - ngx.say("access GET: " .. res.status); + print("access GET: " .. res.status); res = ngx.location.capture("/memc", { method = ngx.HTTP_PUT, body = "hello" }); - ngx.say("access PUT: " .. res.status); + print("access PUT: " .. res.status); res = ngx.location.capture("/memc"); - ngx.say("access cached: " .. res.body); - + print("access cached: " .. res.body); '; content_by_lua ' @@ -228,14 +231,18 @@ world\x03\x04\xff --- request GET /lua --- response_body +content GET: 404 +content PUT: 201 +content cached: hello + +--- grep_error_log eval: qr/(?:rewrite|access) .+?(?= while )/ +--- grep_error_log_out rewrite GET: 404 rewrite PUT: 201 rewrite cached: hello access GET: 404 access PUT: 201 access cached: hello -content GET: 404 -content PUT: 201 -content cached: hello +--- log_level: info diff --git a/t/024-access/sanity.t b/t/024-access/sanity.t index 51baeee65e..fc167613c0 100644 --- a/t/024-access/sanity.t +++ b/t/024-access/sanity.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 8); +plan tests => repeat_each() * (blocks() * 2 + 11); #no_diff(); no_long_string(); @@ -698,3 +698,48 @@ GET /lua?a=1&b=2 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ + + +=== TEST 37: use of ngx.say() in access_by_lua without exiting with 200+. +--- config + location /t { + access_by_lua "ngx.say('test')"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + + + +=== TEST 38: use of ngx.say() in access_by_lua without exiting with 200+. (with explicit ngx.eof()) +--- config + location /t { + access_by_lua "ngx.say('test') ngx.eof()"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + + + +=== TEST 39: use of ngx.say() in access_by_lua without exiting with 200+. (with IO) +--- config + location /t { + access_by_lua "ngx.say('test') ngx.sleep(0.001)"; + echo_exec /t2; + } +--- request + GET /t +--- response_body +test +--- no_error_log +[alert] + diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index 654c6d5e0e..06873c1c4c 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(10); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 4); #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -543,21 +543,21 @@ res4.body = f location /main { rewrite_by_lua ' local res = ngx.location.capture("/a") - ngx.say("rewrite a: " .. res.body) + print("rewrite a: " .. res.body) res = ngx.location.capture("/b") - ngx.say("rewrite b: " .. res.body) + print("rewrite b: " .. res.body) res = ngx.location.capture("/c") - ngx.say("rewrite c: " .. res.body) + print("rewrite c: " .. res.body) '; access_by_lua ' local res = ngx.location.capture("/A") - ngx.say("access A: " .. res.body) + print("access A: " .. res.body) res = ngx.location.capture("/B") - ngx.say("access B: " .. res.body) + print("access B: " .. res.body) '; content_by_lua ' @@ -594,14 +594,18 @@ res4.body = f --- request GET /main --- response_body +content d: d +content e: e +content f: f + +--- log_level: info +--- grep_error_log eval: qr/rewrite .+?(?= while )|access .+?(?=,)/ +--- grep_error_log_out rewrite a: a rewrite b: b rewrite c: c access A: A access B: B -content d: d -content e: e -content f: f @@ -612,17 +616,17 @@ content f: f local a, b, c = ngx.location.capture_multi{ {"/a"}, {"/b"}, {"/c"}, } - ngx.say("rewrite a: " .. a.body) - ngx.say("rewrite b: " .. b.body) - ngx.say("rewrite c: " .. c.body) + print("rewrite a: " .. a.body) + print("rewrite b: " .. b.body) + print("rewrite c: " .. c.body) '; access_by_lua ' local A, B = ngx.location.capture_multi{ {"/A"}, {"/B"}, } - ngx.say("access A: " .. A.body) - ngx.say("access B: " .. B.body) + print("access A: " .. A.body) + print("access B: " .. B.body) '; content_by_lua ' @@ -703,14 +707,17 @@ F(ngx_http_lua_handle_subreq_responses) { } --- response_body +content d: d +content e: e +content f: f +--- log_level: info +--- grep_error_log eval: qr/rewrite .+?(?= while )|access .+?(?=,)/ +--- grep_error_log_out rewrite a: a rewrite b: b rewrite c: c access A: A access B: B -content d: d -content e: e -content f: f diff --git a/t/033-ctx.t b/t/033-ctx.t index e9b972bfac..8301bacc01 100644 --- a/t/033-ctx.t +++ b/t/033-ctx.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 3 + 7); +plan tests => repeat_each() * (blocks() * 3 + 8); #no_diff(); #no_long_string(); @@ -39,7 +39,7 @@ GET /lua --- config location /lua { rewrite_by_lua ' - ngx.say("foo = ", ngx.ctx.foo) + print("foo = ", ngx.ctx.foo) ngx.ctx.foo = 76 '; access_by_lua ' @@ -52,10 +52,13 @@ GET /lua --- request GET /lua --- response_body -foo = nil 79 --- no_error_log [error] +--- grep_error_log eval: qr/foo = [^,]+/ +--- log_level: info +--- grep_error_log_out +foo = nil From 32960150fff46facf6249cb9928e59b77a9e4228 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 22 May 2014 11:37:16 -0700 Subject: [PATCH 0548/1981] minor doc love. --- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index c8514b8ee7..865ca888af 100644 --- a/README.markdown +++ b/README.markdown @@ -1190,7 +1190,7 @@ location /foo { } ``` -Note that the following API functions are currently disabled within this context: +Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) * Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) @@ -6519,7 +6519,7 @@ Bugs and Patches Please submit bug reports, wishlists, or patches by -1. creating a ticket on the [GitHub Issue Tracker](http://github.com/openresty/lua-nginx-module/issues), +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-nginx-module/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 7aa04e3c90..9aa24fb914 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -889,7 +889,7 @@ When the Lua code may change the length of the response body, then it is require } -Note that the following API functions are currently disabled within this context: +Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) * Control API functions (e.g., [[#ngx.exit|ngx.exit]] and [[#ngx.exec|ngx.exec]]) @@ -5519,7 +5519,7 @@ The [https://groups.google.com/group/openresty openresty] mailing list is for Ch Please submit bug reports, wishlists, or patches by -# creating a ticket on the [http://github.com/openresty/lua-nginx-module/issues GitHub Issue Tracker], +# creating a ticket on the [https://github.com/openresty/lua-nginx-module/issues GitHub Issue Tracker], # or posting to the [[#Community|OpenResty community]]. = TODO = From ec78bf1019e10be87e81f457e0ce1e70b175683e Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 22 May 2014 11:37:55 -0700 Subject: [PATCH 0549/1981] fixed a source line exceeding 80 cols. --- src/ngx_http_lua_regex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index a66b06c4f7..022dc2ac99 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -2235,8 +2235,8 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, re->captures = cap; re->replace = NULL; - /* only for (stap) debugging, the pointer might be invalid when the string is - * collected later on.... */ + /* only for (stap) debugging, the pointer might be invalid when the + * string is collected later on.... */ re->pattern = pat; return re; From 4f0be44f75337b8886bc02552672b836e6f8fe13 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 22 May 2014 12:45:44 -0700 Subject: [PATCH 0550/1981] doc: added more explanation for some user FAQs. --- README.markdown | 6 ++++++ doc/HttpLuaModule.wiki | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/README.markdown b/README.markdown index 865ca888af..9c68798e76 100644 --- a/README.markdown +++ b/README.markdown @@ -613,6 +613,8 @@ But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. +Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua_variable_scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). + Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: * Logging APIs: [ngx.log](#ngxlog) and [print](#print), @@ -1343,6 +1345,8 @@ lua_shared_dict Declares a shared memory zone, ``, to serve as storage for the shm based Lua dictionary `ngx.shared.`. +Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. + The `` argument accepts size units such as `k` and `m`: ```nginx @@ -4461,6 +4465,8 @@ ngx.shared.DICT Fetching the shm-based Lua dictionary object for the shared memory zone named `DICT` defined by the [lua_shared_dict](#lua_shared_dict) directive. +Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. + The resulting object `dict` has the following methods: * [get](#ngxshareddictget) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9aa24fb914..e5d2cb64f5 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -371,6 +371,8 @@ But note that, the [[#lua_shared_dict|lua_shared_dict]]'s shm storage will not b Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [http://en.wikipedia.org/wiki/Copy-on-write Copy-on-write (COW)] feature provided by many operating systems among all the worker processes, thus saving a lot of memory. +Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [[#Lua_Variable_Scope|Lua Variable Scope]] section for more details). The recommended way is to use proper [http://www.lua.org/manual/5.1/manual.html#5.3 Lua module] files (but do not use the standard Lua function [http://www.lua.org/manual/5.1/manual.html#pdf-module module()] to define Lua modules because it pollutes the global namespace as well) and call [http://www.lua.org/manual/5.1/manual.html#pdf-require require()] to load your own module files in init_by_lua or other contexts ([http://www.lua.org/manual/5.1/manual.html#pdf-require require()] does cache the loaded Lua modules in the global package.loaded table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). + Only a small set of the [[#Nginx API for Lua|Nginx API for Lua]] is supported in this context: * Logging APIs: [[#ngx.log|ngx.log]] and [[#print|print]], @@ -1026,6 +1028,8 @@ This also applies to [[#access_by_lua|access_by_lua]] and [[#access_by_lua_file| Declares a shared memory zone, , to serve as storage for the shm based Lua dictionary ngx.shared.. +Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. + The argument accepts size units such as k and m: @@ -3727,6 +3731,8 @@ This feature was first introduced in the v0.2.1rc15 release. Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by the [[#lua_shared_dict|lua_shared_dict]] directive. +Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. + The resulting object dict has the following methods: * [[#ngx.shared.DICT.get|get]] From 34ab51f89f69fde41bd6ef95103b7538c8831af7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 22 May 2014 14:53:15 -0700 Subject: [PATCH 0551/1981] updated tests to reflect recent changes in rewrite_by_lua* and access_by_lua*. --- t/023-rewrite/on-abort.t | 16 +----- t/023-rewrite/uthread-exec.t | 3 - t/023-rewrite/uthread-exit.t | 45 --------------- t/023-rewrite/uthread-redirect.t | 3 - t/023-rewrite/uthread-spawn.t | 98 +++----------------------------- t/024-access/on-abort.t | 19 +------ t/024-access/uthread-exec.t | 3 - t/024-access/uthread-exit.t | 45 --------------- t/024-access/uthread-redirect.t | 3 - t/024-access/uthread-spawn.t | 78 ++----------------------- t/097-uthread-rewrite.t | 3 - 11 files changed, 18 insertions(+), 298 deletions(-) diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index f971f6ca22..7cadd1ef35 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -395,7 +395,6 @@ callback done: +OK ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; - content_by_lua return; } --- request GET /t @@ -405,8 +404,6 @@ GET /t --- stap_out terminate 1: ok delete thread 1 -terminate 2: ok -delete thread 2 lua req cleanup --- timeout: 0.2 @@ -435,7 +432,6 @@ main handler done ngx.say("done") '; - content_by_lua return; } --- request GET /t @@ -446,10 +442,8 @@ GET /t create 2 in 1 terminate 1: ok delete thread 1 -delete thread 2 -terminate 3: ok -delete thread 3 lua req cleanup +delete thread 2 --- response_body done @@ -597,10 +591,8 @@ terminate 1: ok delete thread 1 terminate 3: ok delete thread 3 -delete thread 2 -terminate 4: ok -delete thread 4 lua req cleanup +delete thread 2 --- wait: 0.5 --- response_body @@ -652,10 +644,8 @@ GET /t create 2 in 1 terminate 1: ok delete thread 1 -delete thread 2 -terminate 3: ok -delete thread 3 lua req cleanup +delete thread 2 --- response_body 2: cannot set on_abort: duplicate call diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index 54e677cb49..96987dd44b 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -281,7 +281,6 @@ hello foo ngx.location.capture("/sleep") ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -340,8 +339,6 @@ expire timer 200 terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index 9bda522672..953ee4cbe0 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -36,7 +36,6 @@ __DATA__ ngx.sleep(1) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -76,8 +75,6 @@ spawn user thread 2 in 1 terminate 2: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before @@ -103,7 +100,6 @@ hello in thread ngx.sleep(1) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -161,8 +157,6 @@ lua sleep cleanup delete timer 1000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -194,7 +188,6 @@ after ngx.thread.spawn(g) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -256,8 +249,6 @@ lua sleep cleanup delete timer 1000 delete thread 2 delete thread 3 -terminate 4: ok -delete thread 4 free request --- response_body @@ -282,7 +273,6 @@ f ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -295,8 +285,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- wait: 0.1 --- response_body @@ -331,7 +319,6 @@ exiting the user thread end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -403,8 +390,6 @@ lua tcp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -440,7 +425,6 @@ after end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -512,8 +496,6 @@ lua udp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -547,7 +529,6 @@ after end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -605,8 +586,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -655,7 +634,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -708,8 +686,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -764,7 +740,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -817,8 +792,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -861,7 +834,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -914,8 +886,6 @@ lua udp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -953,7 +923,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request POST /lua @@ -1010,8 +979,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1043,7 +1010,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request POST /lua @@ -1098,8 +1064,6 @@ lua req body cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1131,7 +1095,6 @@ after ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -1186,8 +1149,6 @@ expire timer 200 terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1216,7 +1177,6 @@ attempt to abort with pending subrequests ngx.location.capture("/sleep") ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -1277,8 +1237,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1307,7 +1265,6 @@ attempt to abort with pending subrequests } ngx.say("end") '; - content_by_lua return; } location = /echo { @@ -1372,8 +1329,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t index 65c1c2ca72..176f9d514b 100644 --- a/t/023-rewrite/uthread-redirect.t +++ b/t/023-rewrite/uthread-redirect.t @@ -39,7 +39,6 @@ __DATA__ } ngx.say("end") '; - content_by_lua return; } location = /echo { @@ -104,8 +103,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index c1b8c26c59..548c176362 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -32,7 +32,6 @@ __DATA__ ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -56,8 +55,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before @@ -88,7 +85,6 @@ after ngx.thread.spawn(g) ngx.say("after 2") '; - content_by_lua return; } --- request GET /lua @@ -105,8 +101,6 @@ terminate 1: ok delete thread 2 delete thread 3 delete thread 1 -terminate 4: ok -delete thread 4 --- response_body before 1 @@ -134,7 +128,6 @@ after 2 ngx.thread.spawn(f) ngx.say("after thread create") '; - content_by_lua return; } --- request GET /lua @@ -147,8 +140,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -184,7 +175,6 @@ after sleep ngx.thread.spawn(g) ngx.say("2: after thread create") '; - content_by_lua return; } --- request GET /lua @@ -201,8 +191,6 @@ terminate 3: ok delete thread 3 terminate 2: ok delete thread 2 -terminate 4: ok -delete thread 4 --- wait: 0.1 --- response_body @@ -230,7 +218,6 @@ delete thread 4 ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -243,8 +230,6 @@ terminate 2: fail terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body after @@ -267,7 +252,6 @@ lua user thread aborted: runtime error: rewrite_by_lua:3: attempt to call field ngx.thread.spawn(f) ngx.say("after thread create") '; - content_by_lua return; } location /proxy { @@ -289,8 +273,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -318,7 +300,6 @@ after capture: hello world local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) '; - content_by_lua return; } location /proxy { @@ -344,8 +325,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -374,7 +353,6 @@ after capture: hello foo local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) '; - content_by_lua return; } location /proxy { @@ -401,8 +379,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -442,7 +418,6 @@ capture: hello bar local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) '; - content_by_lua return; } location /proxy { @@ -478,8 +453,6 @@ delete thread 2 delete thread 1 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body before thread 1 create @@ -514,7 +487,6 @@ g: after capture: hello bah ngx.thread.spawn(f) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -531,8 +503,6 @@ delete thread 1 terminate 2: ok delete thread 3 delete thread 2 -terminate 4: ok -delete thread 4 --- response_body before f @@ -564,7 +534,6 @@ after g ngx.thread.spawn(f) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -581,8 +550,6 @@ terminate 2: ok delete thread 2 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body before f @@ -608,7 +575,6 @@ hello in g() ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -621,8 +587,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body status: running @@ -643,7 +607,6 @@ status: running ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -656,8 +619,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body status: zombie @@ -684,7 +645,6 @@ status: zombie ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -699,8 +659,6 @@ delete thread 1 terminate 3: ok terminate 2: ok delete thread 2 -terminate 4: ok -delete thread 4 --- response_body status: normal @@ -728,7 +686,6 @@ status: normal coroutine.resume(co) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -743,8 +700,6 @@ terminate 2: ok delete thread 3 terminate 1: ok delete thread 1 -terminate 4: ok -delete thread 4 --- response_body before f @@ -783,7 +738,6 @@ after f yield(self) ngx.say("4") '; - content_by_lua return; } --- request GET /lua @@ -796,8 +750,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body 0 @@ -841,7 +793,6 @@ f 3 ngx.thread.spawn(g) ngx.say("done") '; - content_by_lua return; } --- request GET /lua @@ -858,8 +809,6 @@ terminate 2: ok delete thread 2 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body f 1 @@ -889,7 +838,6 @@ g 3 ngx.say("after") ngx.flush(true) '; - content_by_lua return; } --- request GET /lua @@ -902,8 +850,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before @@ -931,7 +877,6 @@ after ngx.thread.spawn(f) ngx.thread.spawn(g) '; - content_by_lua return; } --- request GET /lua @@ -956,9 +901,7 @@ terminate 3: ok terminate 1: ok delete thread 2 delete thread 3 -delete thread 1) -terminate 4: ok -delete thread 4$ +delete thread 1)$ --- response_body hello from f @@ -998,7 +941,6 @@ hello from g ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -1011,8 +953,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before @@ -1049,7 +989,6 @@ received: OK ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -1062,16 +1001,12 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 |create 2 in 1 spawn user thread 2 in 1 terminate 2: ok terminate 1: ok delete thread 2 -delete thread 1 -terminate 3: ok -delete thread 3)$ +delete thread 1)$ --- udp_listen: 12345 --- udp_query: blah @@ -1121,9 +1056,7 @@ spawn user thread 2 in 1 terminate 1: ok delete thread 1 terminate 2: ok -delete thread 2) -terminate 3: ok -delete thread 3$ +delete thread 2)$ --- response_body_like chop ^(?:before @@ -1156,7 +1089,6 @@ body: hello world)$ ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request POST /lua @@ -1174,9 +1106,7 @@ spawn user thread 2 in 1 terminate 1: ok delete thread 1 terminate 2: ok -delete thread 2) -terminate 3: ok -delete thread 3$ +delete thread 2)$ --- response_body_like chop ^(?:before @@ -1210,7 +1140,6 @@ body: hello world)$ ngx.say("ok") '; - content_by_lua return; } location ~ ^/proxy/(\d+) { @@ -1257,9 +1186,7 @@ post subreq: /proxy/2 rc=404, status=0 a=0 subrequest /proxy/2 done terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 -finalize request /t: rc:0 c:1 a:1 +finalize request /t: rc:200 c:1 a:1 (?:finalize request /t: rc:0 c:1 a:1)?$ --- response_body @@ -1292,7 +1219,6 @@ status: 404 ngx.say("ok") '; - content_by_lua return; } location ~ ^/proxy/(\d+) { @@ -1338,9 +1264,7 @@ delete thread 4 terminate 3: ok delete thread 3 terminate 2: ok -delete thread 2) -terminate 7: ok -delete thread 7 +delete thread 2)$ --- response_body ok @@ -1375,7 +1299,6 @@ status: 404 ngx.say("ok") '; - content_by_lua return; } location ~ ^/proxy/(\d+) { @@ -1433,9 +1356,7 @@ post subreq: /proxy/2 rc=0, status=201 a=0 subrequest /proxy/2 done terminate 3: ok delete thread 3 -terminate 6: ok -delete thread 6 -finalize request /t: rc:0 c:1 a:1 +finalize request /t: rc:200 c:1 a:1 (?:finalize request /t: rc:0 c:1 a:1)?$ --- response_body @@ -1468,7 +1389,6 @@ status: 201 ngx.say("ok") '; - content_by_lua return; } location ~ ^/proxy/(\d+) { @@ -1520,9 +1440,7 @@ post subreq: /proxy/2 rc=204, status=204 a=0 subrequest /proxy/2 done terminate 3: ok delete thread 3 -terminate 6: ok -delete thread 6 -finalize request /t: rc:0 c:1 a:1 +finalize request /t: rc:200 c:1 a:1 (?:finalize request /t: rc:0 c:1 a:1)?$ --- response_body diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 8fff56f3c9..f4f243e16d 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -232,7 +232,6 @@ on abort called ngx.location.capture("/sleep") '; - content_by_lua return; } location = /sleep { @@ -394,7 +393,6 @@ callback done: +OK ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; - content_by_lua return; } --- request GET /t @@ -404,8 +402,6 @@ GET /t --- stap_out terminate 1: ok delete thread 1 -terminate 2: ok -delete thread 2 lua req cleanup --- timeout: 0.2 @@ -434,7 +430,6 @@ main handler done ngx.say("done") '; - content_by_lua return; } --- request GET /t @@ -445,10 +440,8 @@ GET /t create 2 in 1 terminate 1: ok delete thread 1 -delete thread 2 -terminate 3: ok -delete thread 3 lua req cleanup +delete thread 2 --- response_body done @@ -581,7 +574,6 @@ on abort called ngx.say("done") end) '; - content_by_lua return; } --- request GET /t @@ -596,10 +588,8 @@ terminate 1: ok delete thread 1 terminate 3: ok delete thread 3 -delete thread 2 -terminate 4: ok -delete thread 4 lua req cleanup +delete thread 2 --- response_body done @@ -639,7 +629,6 @@ main handler done ngx.say("done") end) '; - content_by_lua return; } --- request GET /t @@ -650,10 +639,8 @@ GET /t create 2 in 1 terminate 1: ok delete thread 1 -delete thread 2 -terminate 3: ok -delete thread 3 lua req cleanup +delete thread 2 --- response_body 2: cannot set on_abort: duplicate call diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 6c0d63747a..1a80bca814 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -282,7 +282,6 @@ hello foo ngx.location.capture("/sleep") ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -341,8 +340,6 @@ expire timer 200 terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 273cb5c533..f8768737ae 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -36,7 +36,6 @@ __DATA__ ngx.sleep(1) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -76,8 +75,6 @@ spawn user thread 2 in 1 terminate 2: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before @@ -103,7 +100,6 @@ hello in thread ngx.sleep(1) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -161,8 +157,6 @@ lua sleep cleanup delete timer 1000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -194,7 +188,6 @@ after ngx.thread.spawn(g) ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -256,8 +249,6 @@ lua sleep cleanup delete timer 1000 delete thread 2 delete thread 3 -terminate 4: ok -delete thread 4 free request --- response_body @@ -282,7 +273,6 @@ f ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -295,8 +285,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- wait: 0.1 --- response_body @@ -331,7 +319,6 @@ exiting the user thread end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -394,8 +381,6 @@ lua tcp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -430,7 +415,6 @@ after end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -493,8 +477,6 @@ lua udp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -528,7 +510,6 @@ after end ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -586,8 +567,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -636,7 +615,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -689,8 +667,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -745,7 +721,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -798,8 +773,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body @@ -842,7 +815,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request GET /lua @@ -895,8 +867,6 @@ lua udp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -934,7 +904,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request POST /lua @@ -991,8 +960,6 @@ lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1024,7 +991,6 @@ after ngx.say("end") '; - content_by_lua return; } --- request POST /lua @@ -1079,8 +1045,6 @@ lua req body cleanup delete timer 12000 delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1112,7 +1076,6 @@ after ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -1167,8 +1130,6 @@ expire timer 200 terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1197,7 +1158,6 @@ attempt to abort with pending subrequests ngx.location.capture("/sleep") ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -1258,8 +1218,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 @@ -1288,7 +1246,6 @@ attempt to abort with pending subrequests } ngx.say("end") '; - content_by_lua return; } location = /echo { @@ -1353,8 +1310,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- wait: 0.1 diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t index 94d35e4460..22db59c01d 100644 --- a/t/024-access/uthread-redirect.t +++ b/t/024-access/uthread-redirect.t @@ -39,7 +39,6 @@ __DATA__ } ngx.say("end") '; - content_by_lua return; } location = /echo { @@ -104,8 +103,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index 49139f3032..db704995c9 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -32,7 +32,6 @@ __DATA__ ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -56,8 +55,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before @@ -88,7 +85,6 @@ after ngx.thread.spawn(g) ngx.say("after 2") '; - content_by_lua return; } --- request GET /lua @@ -105,8 +101,6 @@ terminate 1: ok delete thread 2 delete thread 3 delete thread 1 -terminate 4: ok -delete thread 4 --- response_body before 1 @@ -134,7 +128,6 @@ after 2 ngx.thread.spawn(f) ngx.say("after thread create") '; - content_by_lua return; } --- request GET /lua @@ -147,8 +140,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -184,7 +175,6 @@ after sleep ngx.thread.spawn(g) ngx.say("2: after thread create") '; - content_by_lua return; } --- request GET /lua @@ -201,8 +191,6 @@ terminate 3: ok delete thread 3 terminate 2: ok delete thread 2 -terminate 4: ok -delete thread 4 --- wait: 0.1 --- response_body @@ -230,7 +218,6 @@ delete thread 4 ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -243,8 +230,6 @@ terminate 2: fail terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body after @@ -267,7 +252,6 @@ lua user thread aborted: runtime error: access_by_lua:3: attempt to call field ' ngx.thread.spawn(f) ngx.say("after thread create") '; - content_by_lua return; } location /proxy { @@ -289,8 +273,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -318,7 +300,6 @@ after capture: hello world local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) '; - content_by_lua return; } location /proxy { @@ -344,8 +325,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -401,8 +380,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body before thread create @@ -442,7 +419,6 @@ capture: hello bar local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) '; - content_by_lua return; } location /proxy { @@ -478,8 +454,6 @@ delete thread 2 delete thread 1 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body before thread 1 create @@ -514,7 +488,6 @@ g: after capture: hello bah ngx.thread.spawn(f) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -531,8 +504,6 @@ delete thread 1 terminate 2: ok delete thread 3 delete thread 2 -terminate 4: ok -delete thread 4 --- response_body before f @@ -564,7 +535,6 @@ after g ngx.thread.spawn(f) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -581,8 +551,6 @@ terminate 2: ok delete thread 2 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body before f @@ -608,7 +576,6 @@ hello in g() ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -621,8 +588,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body status: running @@ -643,7 +608,6 @@ status: running ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -656,8 +620,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body status: zombie @@ -684,7 +646,6 @@ status: zombie ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; - content_by_lua return; } --- request GET /lua @@ -699,8 +660,6 @@ delete thread 1 terminate 3: ok terminate 2: ok delete thread 2 -terminate 4: ok -delete thread 4 --- response_body status: normal @@ -728,7 +687,6 @@ status: normal coroutine.resume(co) ngx.say("after f") '; - content_by_lua return; } --- request GET /lua @@ -743,8 +701,6 @@ terminate 2: ok delete thread 3 terminate 1: ok delete thread 1 -terminate 4: ok -delete thread 4 --- response_body before f @@ -783,7 +739,6 @@ after f yield(self) ngx.say("4") '; - content_by_lua return; } --- request GET /lua @@ -796,8 +751,6 @@ terminate 2: ok terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 --- response_body 0 @@ -841,7 +794,6 @@ f 3 ngx.thread.spawn(g) ngx.say("done") '; - content_by_lua return; } --- request GET /lua @@ -858,8 +810,6 @@ terminate 2: ok delete thread 2 terminate 3: ok delete thread 3 -terminate 4: ok -delete thread 4 --- response_body f 1 @@ -889,7 +839,6 @@ g 3 ngx.say("after") ngx.flush(true) '; - content_by_lua return; } --- request GET /lua @@ -902,8 +851,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before @@ -931,7 +878,6 @@ after ngx.thread.spawn(f) ngx.thread.spawn(g) '; - content_by_lua return; } --- request GET /lua @@ -956,9 +902,7 @@ terminate 3: ok terminate 1: ok delete thread 2 delete thread 3 -delete thread 1) -terminate 4: ok -delete thread 4$ +delete thread 1)$ --- response_body hello from f @@ -998,7 +942,6 @@ hello from g ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -1011,8 +954,6 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 --- response_body before @@ -1049,7 +990,6 @@ received: OK ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request GET /lua @@ -1062,16 +1002,12 @@ terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 -terminate 3: ok -delete thread 3 |create 2 in 1 spawn user thread 2 in 1 terminate 2: ok terminate 1: ok delete thread 2 -delete thread 1 -terminate 3: ok -delete thread 3)$ +delete thread 1)$ --- udp_listen: 12345 --- udp_query: blah @@ -1103,7 +1039,6 @@ after)$ ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request POST /lua @@ -1121,9 +1056,7 @@ spawn user thread 2 in 1 terminate 1: ok delete thread 1 terminate 2: ok -delete thread 2) -terminate 3: ok -delete thread 3$ +delete thread 2)$ --- response_body_like chop ^(?:before @@ -1156,7 +1089,6 @@ body: hello world)$ ngx.thread.spawn(f) ngx.say("after") '; - content_by_lua return; } --- request POST /lua @@ -1174,9 +1106,7 @@ spawn user thread 2 in 1 terminate 1: ok delete thread 1 terminate 2: ok -delete thread 2) -terminate 3: ok -delete thread 3$ +delete thread 2)$ --- response_body_like chop ^(?:before diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t index 0a1d9655b9..ef152bef0b 100644 --- a/t/097-uthread-rewrite.t +++ b/t/097-uthread-rewrite.t @@ -277,7 +277,6 @@ hello foo ngx.location.capture("/sleep") ngx.say("end") '; - content_by_lua return; } location = /sleep { @@ -342,8 +341,6 @@ post subreq /sleep terminate 1: ok delete thread 2 delete thread 1 -terminate 3: ok -delete thread 3 free request --- response_body From 50dbfcefd1bfa483feeffaf45f323afc08ceebe7 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 22 May 2014 16:04:40 -0700 Subject: [PATCH 0552/1981] feature: added pure C API function ngx_http_lua_ffi_req_start_time for FFI-based implementations of ngx.req.start_time(). --- src/ngx_http_lua_time.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 8d0e368e13..318dfdc281 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -258,6 +258,13 @@ ngx_http_lua_ffi_ngx_now(void) return tp->sec + tp->msec / 1000.0; } + + +int +ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r) +{ + return r->start_sec + r->start_msec / 1000.0; +} #endif /* NGX_HTTP_LUA_NO_FFI_API */ From 8666424db5d5c8cddf2a4f83f318eb80bdcbbc73 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 12:39:32 -0700 Subject: [PATCH 0553/1981] fixed the wrong return type of the ngx_http_lua_ffi_req_start_time function in the previous commit. --- src/ngx_http_lua_time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 318dfdc281..6e7e145c43 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -260,7 +260,7 @@ ngx_http_lua_ffi_ngx_now(void) } -int +double ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r) { return r->start_sec + r->start_msec / 1000.0; From d9fff3b70ac9b79e76c71c1abdb47c5925c3ee94 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 12:48:22 -0700 Subject: [PATCH 0554/1981] feature: added pure C API function ngx_http_lua_ffi_time for FFI-based implementations of ngx.time(). --- src/ngx_http_lua_time.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 6e7e145c43..0b16af6a33 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -265,6 +265,13 @@ ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r) { return r->start_sec + r->start_msec / 1000.0; } + + +int +ngx_http_lua_ffi_time(void) +{ + return ngx_time(); +} #endif /* NGX_HTTP_LUA_NO_FFI_API */ From 99e5171c646131a78bab7e7ca4bf3c5365370405 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 12:51:06 -0700 Subject: [PATCH 0555/1981] renamed ngx_http_lua_ffi_ngx_now to ngx_http_lua_ffi_now. --- src/ngx_http_lua_time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 0b16af6a33..20281432b3 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -250,7 +250,7 @@ ngx_http_lua_inject_req_time_api(lua_State *L) #ifndef NGX_HTTP_LUA_NO_FFI_API double -ngx_http_lua_ffi_ngx_now(void) +ngx_http_lua_ffi_now(void) { ngx_time_t *tp; From e9b8563c32d4ef0510c5a6012defba15aaf9c9b5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 12:53:43 -0700 Subject: [PATCH 0556/1981] optimize: use lua_pushinteger instead of lua_pushnumber in ngx_http_lua_ngx_time(). --- src/ngx_http_lua_time.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 20281432b3..bf50c45044 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -68,8 +68,7 @@ ngx_http_lua_ngx_localtime(lua_State *L) static int ngx_http_lua_ngx_time(lua_State *L) { - lua_pushnumber(L, (lua_Number) ngx_time()); - + lua_pushinteger(L, (lua_Integer) ngx_time()); return 1; } From 9bb1f3586b270b16eeb6db33bdc329cef2c6f398 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 15:43:43 -0700 Subject: [PATCH 0557/1981] the "int" return type of ngx_http_lua_ffi_time might lead to data loss. thanks itpp16 for the report. --- src/ngx_http_lua_time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index bf50c45044..26447309d5 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -266,10 +266,10 @@ ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r) } -int +long ngx_http_lua_ffi_time(void) { - return ngx_time(); + return (long) ngx_time(); } #endif /* NGX_HTTP_LUA_NO_FFI_API */ From 1c3a8416200bc6665f1d79e90013b2e36b901691 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 15:44:31 -0700 Subject: [PATCH 0558/1981] Revert "optimize: use lua_pushinteger instead of lua_pushnumber in ngx_http_lua_ngx_time()." The lua_Integer type might lead to data loss. This reverts commit e9b8563c32d4ef0510c5a6012defba15aaf9c9b5. --- src/ngx_http_lua_time.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 26447309d5..406d5e6133 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -68,7 +68,8 @@ ngx_http_lua_ngx_localtime(lua_State *L) static int ngx_http_lua_ngx_time(lua_State *L) { - lua_pushinteger(L, (lua_Integer) ngx_time()); + lua_pushnumber(L, (lua_Number) ngx_time()); + return 1; } From f9ce770d788510ffa168d80ad61483158d5752bd Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 19:05:44 -0700 Subject: [PATCH 0559/1981] feature: added pure C API functions for FFI-based implementations of ngx.req.get_method(). --- src/ngx_http_lua_req_method.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index fc64d1498b..98d3e2fd50 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -145,4 +145,32 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) return 0; } + +#ifndef NGX_HTTP_LUA_NO_FFI_API +int +ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r) +{ + if (r->connection->fd == -1) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + return r->method; +} + + +int +ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, char *buf, + size_t *len) +{ + if (r->connection->fd == -1) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + *len = ngx_min(r->method_name.len, *len); + ngx_memcpy(buf, r->method_name.data, *len); + return NGX_OK; +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 62b2ac5cb0650f28cbb2bd4fe7e12cf930d24dbe Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 19:44:29 -0700 Subject: [PATCH 0560/1981] feature: added pure C API function for FFI-based implementations of ngx.req.set_method(). --- src/ngx_http_lua_req_method.c | 77 +++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index 98d3e2fd50..39236906fa 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -170,6 +170,83 @@ ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, char *buf, ngx_memcpy(buf, r->method_name.data, *len); return NGX_OK; } + + +int +ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method) +{ + if (r->connection->fd == -1) { + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + switch (method) { + case NGX_HTTP_GET: + r->method_name = ngx_http_lua_get_method; + break; + + case NGX_HTTP_POST: + r->method_name = ngx_http_lua_post_method; + break; + + case NGX_HTTP_PUT: + r->method_name = ngx_http_lua_put_method; + break; + + case NGX_HTTP_HEAD: + r->method_name = ngx_http_lua_head_method; + break; + + case NGX_HTTP_DELETE: + r->method_name = ngx_http_lua_delete_method; + break; + + case NGX_HTTP_OPTIONS: + r->method_name = ngx_http_lua_options_method; + break; + + case NGX_HTTP_MKCOL: + r->method_name = ngx_http_lua_mkcol_method; + break; + + case NGX_HTTP_COPY: + r->method_name = ngx_http_lua_copy_method; + break; + + case NGX_HTTP_MOVE: + r->method_name = ngx_http_lua_move_method; + break; + + case NGX_HTTP_PROPFIND: + r->method_name = ngx_http_lua_propfind_method; + break; + + case NGX_HTTP_PROPPATCH: + r->method_name = ngx_http_lua_proppatch_method; + break; + + case NGX_HTTP_LOCK: + r->method_name = ngx_http_lua_lock_method; + break; + + case NGX_HTTP_UNLOCK: + r->method_name = ngx_http_lua_unlock_method; + break; + + case NGX_HTTP_PATCH: + r->method_name = ngx_http_lua_patch_method; + break; + + case NGX_HTTP_TRACE: + r->method_name = ngx_http_lua_trace_method; + break; + + default: + return NGX_DECLINED; + } + + r->method = method; + return NGX_OK; +} #endif From 3a01812d8876e5c6707c113fbcf3bb7e8cf4f75f Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 20:15:53 -0700 Subject: [PATCH 0561/1981] feature: added a pure C API function for FFI implementations of shdict:flush_all(). --- src/ngx_http_lua_shdict.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index cf81195ffe..88f219bed1 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1802,6 +1802,33 @@ ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, *value = num; return NGX_OK; } + + +int +ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +{ + ngx_queue_t *q; + ngx_http_lua_shdict_node_t *sd; + ngx_http_lua_shdict_ctx_t *ctx; + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + for (q = ngx_queue_head(&ctx->sh->queue); + q != ngx_queue_sentinel(&ctx->sh->queue); + q = ngx_queue_next(q)) + { + sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); + sd->expires = 1; + } + + ngx_http_lua_shdict_expire(ctx, 0); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} #endif /* NGX_HTTP_LUA_NO_FFI_API */ From 31e00155727766c4230ac3daa1bf2d87f7d41b4d Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 21:06:21 -0700 Subject: [PATCH 0562/1981] feature: added a pure C API function for FFI-based implementations of ngx.req.set_header() (single-value only) and ngx.req.clear_header(). --- src/ngx_http_lua_headers.c | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 0703b9c525..083e48cf48 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -1115,6 +1115,55 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, *errmsg = "no memory"; return NGX_ERROR; } + + +int +ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, + const u_char *key, size_t key_len, const u_char *value, size_t value_len) +{ + ngx_str_t k; + ngx_str_t v; + + if (r->connection->fd == -1) { /* fake request */ + return NGX_HTTP_LUA_FFI_BAD_CONTEXT; + } + + if (r->http_version < NGX_HTTP_VERSION_10) { + return NGX_DECLINED; + } + + k.data = ngx_palloc(r->pool, key_len + 1); + if (k.data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(k.data, key, key_len); + k.data[key_len] = '\0'; + + k.len = key_len; + + if (value_len == 0) { + v.data = NULL; + v.len = 0; + + } else { + v.data = ngx_palloc(r->pool, value_len + 1); + if (v.data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(v.data, value, value_len); + v.data[value_len] = '\0'; + } + + v.len = value_len; + + if (ngx_http_lua_set_input_header(r, k, v, 1 /* override */) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} #endif /* NGX_HTTP_LUA_NO_FFI_API */ From d3ab0edd45bffe1b9a36abdf5bff544de436ccee Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Sat, 24 May 2014 21:09:36 -0700 Subject: [PATCH 0563/1981] bugfix: ngx.req.set_method(): we incorrectly modified r->method when the method ID was wrong. --- src/ngx_http_lua_req_method.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index 39236906fa..e328b726e0 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -74,8 +74,6 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) ngx_http_lua_check_fake_request(L, r); - r->method = method; - switch (method) { case NGX_HTTP_GET: r->method_name = ngx_http_lua_get_method; @@ -139,9 +137,10 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) default: return luaL_error(L, "unsupported HTTP method: %d", method); - } + r->method = method; + return 0; } From ec2498a81592150e9ca74c65f05e1644afd7a1f5 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Tue, 27 May 2014 12:44:12 -0700 Subject: [PATCH 0564/1981] added assertions to the coroutine scheduler to ensure that we do not pop or push the wrong number of stack slots for yielded coroutines. --- src/ngx_http_lua_accessby.c | 3 +++ src/ngx_http_lua_common.h | 5 ++++ src/ngx_http_lua_contentby.c | 3 +++ src/ngx_http_lua_coroutine.c | 4 ++++ src/ngx_http_lua_rewriteby.c | 3 +++ src/ngx_http_lua_timer.c | 4 ++++ src/ngx_http_lua_uthread.c | 2 ++ src/ngx_http_lua_util.c | 46 ++++++++++++++++++++++++++++++++++-- 8 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 8c2edc4b9d..05f937999a 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -276,6 +276,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top = 1; +#endif /* }}} */ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 327b589f43..08e6b8f2b0 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -284,6 +284,11 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ +#ifdef ngx_http_lua_assert + int co_top; /* stack top after yielding/creation, + only for sanity checks */ +#endif + int co_ref; /* reference to anchor the thread coroutines (entry coroutine and user threads) in the Lua registry, diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 43bc6559a4..c6d7c2693b 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -72,6 +72,9 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top = 1; +#endif /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 91d08a0739..4bef1de8fb 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -117,6 +117,10 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, *pcoctx = coctx; } +#ifdef ngx_http_lua_assert + coctx->co_top = 1; +#endif + return 1; /* return new coroutine to Lua */ } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 001b383db3..823b0b1e6b 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -270,6 +270,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top = 1; +#endif /* }}} */ diff --git a/src/ngx_http_lua_timer.c b/src/ngx_http_lua_timer.c index 8c496ee024..ebb71ee248 100644 --- a/src/ngx_http_lua_timer.c +++ b/src/ngx_http_lua_timer.c @@ -355,6 +355,10 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) lua_insert(tctx.co, 2); } +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top = 1; +#endif + rc = ngx_http_lua_run_thread(L, r, ctx, n - 1); dd("timer lua run thread: %d", (int) rc); diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index ca1fffd472..368220d035 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -94,6 +94,8 @@ ngx_http_lua_uthread_spawn(lua_State *L) ngx_http_lua_probe_user_thread_spawn(r, L, coctx->co); + dd("yielding with arg %s, top=%d, index-1:%s", luaL_typename(L, -1), + (int) lua_gettop(L), luaL_typename(L, 1)); return lua_yield(L, 1); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index facb55c24e..15fa6dc769 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1058,6 +1058,20 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, dd("cur co status: %d", ctx->cur_co_ctx->co_status); orig_coctx = ctx->cur_co_ctx; + + dd("%p: saved co top: %d, nrets: %d, true top: %d", + orig_coctx->co, + (int) orig_coctx->co_top, (int) nrets, + (int) lua_gettop(orig_coctx->co)); +#if DDEBUG + if (lua_gettop(orig_coctx->co) > 0) { + dd("top elem: %s", luaL_typename(orig_coctx->co, -1)); + } +#endif + + ngx_http_lua_assert(orig_coctx->co_top + nrets + == lua_gettop(orig_coctx->co)); + rv = lua_resume(orig_coctx->co, nrets); #if (NGX_PCRE) @@ -1083,6 +1097,13 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua thread yielded"); +#ifdef ngx_http_lua_assert + dd("%p: saving curr top after yield: %d (co-op: %d)", + orig_coctx->co, + (int) lua_gettop(orig_coctx->co), (int) ctx->co_op); + orig_coctx->co_top = lua_gettop(orig_coctx->co); +#endif + if (r->uri_changed) { return ngx_http_lua_handle_rewrite_jump(L, r, ctx); } @@ -1103,7 +1124,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, case NGX_HTTP_LUA_USER_CORO_NOP: dd("hit! it is the API yield"); - lua_settop(ctx->cur_co_ctx->co, 0); +#ifdef ngx_http_lua_assert + ngx_http_lua_assert(lua_gettop(ctx->cur_co_ctx->co) == 0); +#endif + ctx->cur_co_ctx = NULL; return NGX_AGAIN; @@ -1116,6 +1140,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; nrets = lua_gettop(ctx->cur_co_ctx->co) - 1; dd("nrets = %d", nrets); +#ifdef ngx_http_lua_assert + /* ignore the return value (the thread) already pushed */ + orig_coctx->co_top--; +#endif break; @@ -1133,7 +1161,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, nrets = lua_gettop(old_co); if (nrets) { + dd("moving %d return values to parent", nrets); lua_xmove(old_co, ctx->cur_co_ctx->co, nrets); +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->parent_co_ctx->co_top -= nrets; +#endif } break; @@ -1149,8 +1181,14 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, if (ngx_http_lua_is_thread(ctx)) { ngx_http_lua_probe_thread_yield(r, ctx->cur_co_ctx->co); + /* discard any return values from user + * coroutine.yield()'s arguments */ lua_settop(ctx->cur_co_ctx->co, 0); +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top = 0; +#endif + ngx_http_lua_probe_info("set co running"); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; @@ -1181,10 +1219,14 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_pushboolean(next_co, 1); if (nrets) { + dd("moving %d return values to next co", nrets); lua_xmove(ctx->cur_co_ctx->co, next_co, nrets); +#ifdef ngx_http_lua_assert + ctx->cur_co_ctx->co_top -= nrets; +#endif } - nrets++; + nrets++; /* add the true boolean value */ ctx->cur_co_ctx = next_coctx; From 91e3307fb9f34922041ab1da63b4fa02641fe407 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 May 2014 11:50:49 -0700 Subject: [PATCH 0565/1981] use ngx_http_lua_assert() instead of plain assert() across the code base. --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_bodyfilterby.c | 2 +- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_headerfilterby.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 05f937999a..1979a7cb85 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -221,7 +221,7 @@ ngx_http_lua_access_handler_file(ngx_http_request_t *r) } /* make sure we have a valid code chunk */ - assert(lua_isfunction(L, -1)); + ngx_http_lua_assert(lua_isfunction(L, -1)); return ngx_http_lua_access_by_chunk(L, r); } diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index d224cb05c7..a242fb5661 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -215,7 +215,7 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) } /* make sure we have a valid code chunk */ - assert(lua_isfunction(L, -1)); + ngx_http_lua_assert(lua_isfunction(L, -1)); rc = ngx_http_lua_body_filter_by_chunk(L, r, in); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index c6d7c2693b..c0baede19a 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -258,7 +258,7 @@ ngx_http_lua_content_handler_file(ngx_http_request_t *r) } /* make sure we have a valid code chunk */ - assert(lua_isfunction(L, -1)); + ngx_http_lua_assert(lua_isfunction(L, -1)); return ngx_http_lua_content_by_chunk(L, r); } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index ab66ff7d3c..c54f54c777 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -226,7 +226,7 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) } /* make sure we have a valid code chunk */ - assert(lua_isfunction(L, -1)); + ngx_http_lua_assert(lua_isfunction(L, -1)); return ngx_http_lua_header_filter_by_chunk(L, r); } From a9e0111fe965b5ef4d48075e5d1718f3046d3b96 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 May 2014 13:43:15 -0700 Subject: [PATCH 0566/1981] =?UTF-8?q?doc:=20moved=20important=20sections?= =?UTF-8?q?=20to=20the=20front.=20thanks=20Pierre-Yves=20G=C3=A9rardy=20fo?= =?UTF-8?q?r=20the=20patch=20in=20#371.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.markdown | 298 ++++++++++++++++++++--------------------- doc/HttpLuaModule.wiki | 220 +++++++++++++++--------------- 2 files changed, 259 insertions(+), 259 deletions(-) diff --git a/README.markdown b/README.markdown index 9c68798e76..3ae2871a90 100644 --- a/README.markdown +++ b/README.markdown @@ -17,6 +17,15 @@ Table of Contents * [Version](#version) * [Synopsis](#synopsis) * [Description](#description) +* [Typical Uses](#typical-uses) +* [Nginx Compatibility](#nginx-compatibility) +* [Installation](#installation) + * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Code Repository](#code-repository) +* [Bugs and Patches](#bugs-and-patches) * [Directives](#directives) * [lua_use_default_type](#lua_use_default_type) * [lua_code_cache](#lua_code_cache) @@ -196,15 +205,6 @@ Table of Contents * [Special PCRE Sequences](#special-pcre-sequences) * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) -* [Typical Uses](#typical-uses) -* [Nginx Compatibility](#nginx-compatibility) -* [Code Repository](#code-repository) -* [Installation](#installation) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) * [TODO](#todo) * [Short Term](#short-term) * [Longer Term](#longer-term) @@ -429,6 +429,146 @@ Loaded Lua modules persist in the nginx worker process level resulting in a smal [Back to TOC](#table-of-contents) +Typical Uses +============ + +Just to name a few: + +* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, +* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, +* manipulating response headers in an arbitrary way (by Lua) +* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, +* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, +* doing very complex URL dispatch in Lua at rewrite phase, +* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. + +The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. + +Other scripting language implementations typically struggle to match this performance level. + +The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. + +On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k req/sec using `http_load -p 10`. By contrast, Nginx + php-fpm 5.2.8 + Unix Domain Socket yields 6k req/sec and [Node.js](http://nodejs.org/) v0.6.1 yields 10.2k req/sec for their Hello World equivalents. + +[Back to TOC](#table-of-contents) + +Nginx Compatibility +=================== +The latest module is compatible with the following versions of Nginx: + +* 1.5.x (last tested: 1.5.12) +* 1.4.x (last tested: 1.4.4) +* 1.3.x (last tested: 1.3.11) +* 1.2.x (last tested: 1.2.9) +* 1.1.x (last tested: 1.1.5) +* 1.0.x (last tested: 1.0.15) +* 0.9.x (last tested: 0.9.4) +* 0.8.x >= 0.8.54 (last tested: 0.8.54) + +[Back to TOC](#table-of-contents) + +Installation +============ + +The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple `./configure --with-luajit && make && make install`. + +Alternatively, ngx_lua can be manually compiled into Nginx: + +1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. +1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](http://github.com/simpl/ngx_devel_kit/tags). +1. Download the latest version of ngx_lua [HERE](http://github.com/openresty/lua-nginx-module/tags). +1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) + +Build the source with this module: + +```bash + +wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' +tar -xzvf nginx-1.5.12.tar.gz +cd nginx-1.5.12/ + +# tell nginx's build system where to find LuaJIT 2.0: +export LUAJIT_LIB=/path/to/luajit/lib +export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 + +# tell nginx's build system where to find LuaJIT 2.1: +export LUAJIT_LIB=/path/to/luajit/lib +export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 + +# or tell where to find Lua if using Lua instead: +#export LUA_LIB=/path/to/lua/lib +#export LUA_INC=/path/to/lua/include + +# Here we assume Nginx is to be installed under /opt/nginx/. +./configure --prefix=/opt/nginx \ + --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/lua-nginx-module + +make -j2 +make install +``` + +[Back to TOC](#table-of-contents) + +Installation on Ubuntu 11.10 +---------------------------- + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + +```bash + +apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev +``` + +Everything should be installed correctly, except for one small tweak. + +Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. + +```bash + +ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so +``` + +[Back to TOC](#table-of-contents) + +Community +========= + +[Back to TOC](#table-of-contents) + +English Mailing List +-------------------- + +The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. + +[Back to TOC](#table-of-contents) + +Chinese Mailing List +-------------------- + +The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. + +[Back to TOC](#table-of-contents) + +Code Repository +=============== + +The code repository of this project is hosted on github at [openresty/lua-nginx-module](http://github.com/openresty/lua-nginx-module). + +[Back to TOC](#table-of-contents) + +Bugs and Patches +================ + +Please submit bug reports, wishlists, or patches by + +1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-nginx-module/issues), +1. or posting to the [OpenResty community](#community). + +[Back to TOC](#table-of-contents) + Directives ========== @@ -6390,146 +6530,6 @@ Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx. [Back to TOC](#table-of-contents) -Typical Uses -============ - -Just to name a few: - -* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, -* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, -* manipulating response headers in an arbitrary way (by Lua) -* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, -* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, -* doing very complex URL dispatch in Lua at rewrite phase, -* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. - -The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. - -Other scripting language implementations typically struggle to match this performance level. - -The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. - -On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k req/sec using `http_load -p 10`. By contrast, Nginx + php-fpm 5.2.8 + Unix Domain Socket yields 6k req/sec and [Node.js](http://nodejs.org/) v0.6.1 yields 10.2k req/sec for their Hello World equivalents. - -[Back to TOC](#table-of-contents) - -Nginx Compatibility -=================== -The latest module is compatible with the following versions of Nginx: - -* 1.5.x (last tested: 1.5.12) -* 1.4.x (last tested: 1.4.4) -* 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.9) -* 1.1.x (last tested: 1.1.5) -* 1.0.x (last tested: 1.0.15) -* 0.9.x (last tested: 0.9.4) -* 0.8.x >= 0.8.54 (last tested: 0.8.54) - -[Back to TOC](#table-of-contents) - -Code Repository -=============== - -The code repository of this project is hosted on github at [openresty/lua-nginx-module](http://github.com/openresty/lua-nginx-module). - -[Back to TOC](#table-of-contents) - -Installation -============ - -The [ngx_openresty bundle](http://openresty.org) can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple `./configure --with-luajit && make && make install`. - -Alternatively, ngx_lua can be manually compiled into Nginx: - -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuajIT can be downloaded from the [the LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuajIT and/or Lua. -1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](http://github.com/simpl/ngx_devel_kit/tags). -1. Download the latest version of ngx_lua [HERE](http://github.com/openresty/lua-nginx-module/tags). -1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) - -Build the source with this module: - -```bash - -wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' -tar -xzvf nginx-1.5.12.tar.gz -cd nginx-1.5.12/ - -# tell nginx's build system where to find LuaJIT 2.0: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 - -# tell nginx's build system where to find LuaJIT 2.1: -export LUAJIT_LIB=/path/to/luajit/lib -export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - -# or tell where to find Lua if using Lua instead: -#export LUA_LIB=/path/to/lua/lib -#export LUA_INC=/path/to/lua/include - -# Here we assume Nginx is to be installed under /opt/nginx/. -./configure --prefix=/opt/nginx \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - -make -j2 -make install -``` - -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - -[Back to TOC](#table-of-contents) - -Community -========= - -[Back to TOC](#table-of-contents) - -English Mailing List --------------------- - -The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. - -[Back to TOC](#table-of-contents) - -Chinese Mailing List --------------------- - -The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. - -[Back to TOC](#table-of-contents) - -Bugs and Patches -================ - -Please submit bug reports, wishlists, or patches by - -1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-nginx-module/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - TODO ==== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index e5d2cb64f5..620c65a837 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -211,6 +211,116 @@ The Lua interpreter or LuaJIT instance is shared across all the requests in a si Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. += Typical Uses = + +Just to name a few: + +* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, +* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, +* manipulating response headers in an arbitrary way (by Lua) +* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, +* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, +* doing very complex URL dispatch in Lua at rewrite phase, +* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. + +The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. + +Other scripting language implementations typically struggle to match this performance level. + +The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. + +On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k req/sec using http_load -p 10. By contrast, Nginx + php-fpm 5.2.8 + Unix Domain Socket yields 6k req/sec and [http://nodejs.org/ Node.js] v0.6.1 yields 10.2k req/sec for their Hello World equivalents. + += Nginx Compatibility = +The latest module is compatible with the following versions of Nginx: + +* 1.5.x (last tested: 1.5.12) +* 1.4.x (last tested: 1.4.4) +* 1.3.x (last tested: 1.3.11) +* 1.2.x (last tested: 1.2.9) +* 1.1.x (last tested: 1.1.5) +* 1.0.x (last tested: 1.0.15) +* 0.9.x (last tested: 0.9.4) +* 0.8.x >= 0.8.54 (last tested: 0.8.54) + += Installation = + +The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple ./configure --with-luajit && make && make install. + +Alternatively, ngx_lua can be manually compiled into Nginx: + +# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuajIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. +# Download the latest version of the ngx_devel_kit (NDK) module [http://github.com/simpl/ngx_devel_kit/tags HERE]. +# Download the latest version of ngx_lua [http://github.com/openresty/lua-nginx-module/tags HERE]. +# Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) + +Build the source with this module: + + + wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' + tar -xzvf nginx-1.5.12.tar.gz + cd nginx-1.5.12/ + + # tell nginx's build system where to find LuaJIT 2.0: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 + + # tell nginx's build system where to find LuaJIT 2.1: + export LUAJIT_LIB=/path/to/luajit/lib + export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 + + # or tell where to find Lua if using Lua instead: + #export LUA_LIB=/path/to/lua/lib + #export LUA_INC=/path/to/lua/include + + # Here we assume Nginx is to be installed under /opt/nginx/. + ./configure --prefix=/opt/nginx \ + --add-module=/path/to/ngx_devel_kit \ + --add-module=/path/to/lua-nginx-module + + make -j2 + make install + + +== Installation on Ubuntu 11.10 == + +Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. + +If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: + + +apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev + + +Everything should be installed correctly, except for one small tweak. + +Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. + + +ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so + + += Community = + +== English Mailing List == + +The [https://groups.google.com/group/openresty-en openresty-en] mailing list is for English speakers. + +== Chinese Mailing List == + +The [https://groups.google.com/group/openresty openresty] mailing list is for Chinese speakers. + += Code Repository = + +The code repository of this project is hosted on github at [http://github.com/openresty/lua-nginx-module openresty/lua-nginx-module]. + += Bugs and Patches = + +Please submit bug reports, wishlists, or patches by + +# creating a ticket on the [https://github.com/openresty/lua-nginx-module/issues GitHub Issue Tracker], +# or posting to the [[#Community|OpenResty community]]. + = Directives = == lua_use_default_type == @@ -5418,116 +5528,6 @@ Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], and [[#ngx.req.socket|ngx.req.socket]]. -= Typical Uses = - -Just to name a few: - -* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, -* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, -* manipulating response headers in an arbitrary way (by Lua) -* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, -* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, -* doing very complex URL dispatch in Lua at rewrite phase, -* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. - -The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. - -Other scripting language implementations typically struggle to match this performance level. - -The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. - -On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k req/sec using http_load -p 10. By contrast, Nginx + php-fpm 5.2.8 + Unix Domain Socket yields 6k req/sec and [http://nodejs.org/ Node.js] v0.6.1 yields 10.2k req/sec for their Hello World equivalents. - -= Nginx Compatibility = -The latest module is compatible with the following versions of Nginx: - -* 1.5.x (last tested: 1.5.12) -* 1.4.x (last tested: 1.4.4) -* 1.3.x (last tested: 1.3.11) -* 1.2.x (last tested: 1.2.9) -* 1.1.x (last tested: 1.1.5) -* 1.0.x (last tested: 1.0.15) -* 0.9.x (last tested: 0.9.4) -* 0.8.x >= 0.8.54 (last tested: 0.8.54) - -= Code Repository = - -The code repository of this project is hosted on github at [http://github.com/openresty/lua-nginx-module openresty/lua-nginx-module]. - -= Installation = - -The [http://openresty.org ngx_openresty bundle] can be used to install Nginx, ngx_lua, either one of the standard Lua 5.1 interpreter or LuaJIT 2.0/2.1, as well as a package of powerful companion Nginx modules. The basic installation step is a simple ./configure --with-luajit && make && make install. - -Alternatively, ngx_lua can be manually compiled into Nginx: - -# Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is ''not'' supported yet). LuajIT can be downloaded from the [http://luajit.org/download.html the LuaJIT project website] and Lua 5.1, from the [http://www.lua.org/ Lua project website]. Some distribution package managers also distribute LuajIT and/or Lua. -# Download the latest version of the ngx_devel_kit (NDK) module [http://github.com/simpl/ngx_devel_kit/tags HERE]. -# Download the latest version of ngx_lua [http://github.com/openresty/lua-nginx-module/tags HERE]. -# Download the latest version of Nginx [http://nginx.org/ HERE] (See [[#Nginx Compatibility|Nginx Compatibility]]) - -Build the source with this module: - - - wget 'http://nginx.org/download/nginx-1.5.12.tar.gz' - tar -xzvf nginx-1.5.12.tar.gz - cd nginx-1.5.12/ - - # tell nginx's build system where to find LuaJIT 2.0: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 - - # tell nginx's build system where to find LuaJIT 2.1: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - - # or tell where to find Lua if using Lua instead: - #export LUA_LIB=/path/to/lua/lib - #export LUA_INC=/path/to/lua/include - - # Here we assume Nginx is to be installed under /opt/nginx/. - ./configure --prefix=/opt/nginx \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - - make -j2 - make install - - -== Installation on Ubuntu 11.10 == - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - - -apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev - - -Everything should be installed correctly, except for one small tweak. - -Library name liblua.so has been changed in liblua5.1 package, it only comes with liblua5.1.so, which needs to be symlinked to /usr/lib so it could be found during the configuration process. - - -ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so - - -= Community = - -== English Mailing List == - -The [https://groups.google.com/group/openresty-en openresty-en] mailing list is for English speakers. - -== Chinese Mailing List == - -The [https://groups.google.com/group/openresty openresty] mailing list is for Chinese speakers. - -= Bugs and Patches = - -Please submit bug reports, wishlists, or patches by - -# creating a ticket on the [https://github.com/openresty/lua-nginx-module/issues GitHub Issue Tracker], -# or posting to the [[#Community|OpenResty community]]. - = TODO = == Short Term == From c91e1f5258bd9c075f73b0481cf09e37c6378a07 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Fri, 30 May 2014 14:04:04 -0700 Subject: [PATCH 0567/1981] =?UTF-8?q?doc:=20moved=20the=20"Directives"=20a?= =?UTF-8?q?nd=20"Nginx=20API=20for=20Lua"=20sections=20to=20the=20end=20be?= =?UTF-8?q?cause=20they=20are=20too=20long=20and=20kinda=20boring=20:)=20t?= =?UTF-8?q?hanks=20Pierre-Yves=20G=C3=A9rardy=20for=20the=20patch=20in=20#?= =?UTF-8?q?371.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.markdown | 7527 ++++++++++++++++++++-------------------- doc/HttpLuaModule.wiki | 6899 ++++++++++++++++++------------------ 2 files changed, 7216 insertions(+), 7210 deletions(-) diff --git a/README.markdown b/README.markdown index 3ae2871a90..ef90ac034c 100644 --- a/README.markdown +++ b/README.markdown @@ -26,6 +26,26 @@ Table of Contents * [Chinese Mailing List](#chinese-mailing-list) * [Code Repository](#code-repository) * [Bugs and Patches](#bugs-and-patches) +* [Lua/LuaJIT bytecode support](#lualuajit-bytecode-support) +* [System Environment Variable Support](#system-environment-variable-support) +* [HTTP 1.0 support](#http-10-support) +* [Statically Linking Pure Lua Modules](#statically-linking-pure-lua-modules) +* [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) +* [Known Issues](#known-issues) + * [TCP socket connect operation issues](#tcp-socket-connect-operation-issues) + * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) + * [Lua Variable Scope](#lua-variable-scope) + * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) + * [Special PCRE Sequences](#special-pcre-sequences) + * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) + * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) +* [TODO](#todo) + * [Short Term](#short-term) + * [Longer Term](#longer-term) +* [Changes](#changes) +* [Test Suite](#test-suite) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) * [Directives](#directives) * [lua_use_default_type](#lua_use_default_type) * [lua_code_cache](#lua_code_cache) @@ -192,26 +212,6 @@ Table of Contents * [coroutine.wrap](#coroutinewrap) * [coroutine.running](#coroutinerunning) * [coroutine.status](#coroutinestatus) -* [Lua/LuaJIT bytecode support](#lualuajit-bytecode-support) -* [System Environment Variable Support](#system-environment-variable-support) -* [HTTP 1.0 support](#http-10-support) -* [Statically Linking Pure Lua Modules](#statically-linking-pure-lua-modules) -* [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) -* [Known Issues](#known-issues) - * [TCP socket connect operation issues](#tcp-socket-connect-operation-issues) - * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) - * [Lua Variable Scope](#lua-variable-scope) - * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Special PCRE Sequences](#special-pcre-sequences) - * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) - * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) -* [TODO](#todo) - * [Short Term](#short-term) - * [Longer Term](#longer-term) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) Status ====== @@ -448,8 +448,6 @@ Other scripting language implementations typically struggle to match this perfor The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. -On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k req/sec using `http_load -p 10`. By contrast, Nginx + php-fpm 5.2.8 + Unix Domain Socket yields 6k req/sec and [Node.js](http://nodejs.org/) v0.6.1 yields 10.2k req/sec for their Hello World equivalents. - [Back to TOC](#table-of-contents) Nginx Compatibility @@ -569,6098 +567,6103 @@ Please submit bug reports, wishlists, or patches by [Back to TOC](#table-of-contents) -Directives -========== - -[Back to TOC](#table-of-contents) - -lua_use_default_type --------------------- -**syntax:** *lua_use_default_type on | off* +Lua/LuaJIT bytecode support +=========================== -**default:** *lua_use_default_type on* +As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. -**context:** *http, server, location, location if* +Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. If you do not want a default `Content-Type` response header for your Lua request handlers, then turn this directive off. +```bash -This directive is turned on by default. +/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac +``` -This directive was first introduced in the `v0.9.1` release. +The `-bg` option can be used to include debug information in the LuaJIT bytecode file: -[Back to TOC](#table-of-contents) +```bash -lua_code_cache --------------- -**syntax:** *lua_code_cache on | off* +/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac +``` -**default:** *lua_code_cache on* +Please refer to the official LuaJIT documentation on the `-b` option for more details: -**context:** *http, server, location, location if* + -Enables or disables the Lua code cache for Lua code in `*_by_lua_file` directives (like [set_by_lua_file](#set_by_lua_file) and -[content_by_lua_file](#content_by_lua_file)) and Lua modules. +Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. -When turning off, every request served by ngx_lua will run in a separate Lua VM instance, starting from the `0.9.3` release. So the Lua files referenced in [set_by_lua_file](#set_by_lua_file), -[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), -and etc will not be cached -and all Lua modules used will be loaded from scratch. With this in place, developers can adopt an edit-and-refresh approach. +Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: -Please note however, that Lua code written inlined within nginx.conf -such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), -[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will not be updated when you edit the inlined Lua code in your `nginx.conf` file because only the Nginx config file parser can correctly parse the `nginx.conf` -file and the only way is to reload the config file -by sending a `HUP` signal or just to restart Nginx. +```bash -Even when the code cache is enabled, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file cannot be cached (unless you cache the results yourself). Usually you can either use the [init_by_lua](#init_by_lua) -or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules -and load them via `require`. +luac -o /path/to/output_file.luac /path/to/input_file.lua +``` -The ngx_lua module does not support the `stat` mode available with the -Apache `mod_lua` module (yet). +Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: -Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. +```bash -[Back to TOC](#table-of-contents) +luac -s -o /path/to/output_file.luac /path/to/input_file.lua +``` -lua_regex_cache_max_entries ---------------------------- -**syntax:** *lua_regex_cache_max_entries <num>* +Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: -**default:** *lua_regex_cache_max_entries 1024* -**context:** *http* + [error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac -Specifies the maximum number of entries allowed in the worker process level compiled regex cache. -The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. +Loading bytecode files via the Lua primitives like `require` and `dofile` should always work as expected. -The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: +[Back to TOC](#table-of-contents) +System Environment Variable Support +=================================== - 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... +If you want to access the system environment variable, say, `foo`, in Lua via the standard Lua API [os.getenv](http://www.lua.org/manual/5.1/manual.html#pdf-os.getenv), then you should also list this environment variable name in your `nginx.conf` file via the [env directive](http://nginx.org/en/docs/ngx_core_module.html#env). For example, +```nginx -Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. +env foo; +``` [Back to TOC](#table-of-contents) -lua_regex_match_limit ---------------------- -**syntax:** *lua_regex_match_limit <num>* - -**default:** *lua_regex_match_limit 0* +HTTP 1.0 support +================ -**context:** *http* +The HTTP 1.0 protocol does not support chunked output and requires an explicit `Content-Length` header when the response body is not empty in order to support the HTTP 1.0 keep-alive. +So when a HTTP 1.0 request is made and the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`, ngx_lua will buffer the +output of [ngx.say](#ngxsay) and [ngx.print](#ngxprint) calls and also postpone sending response headers until all the response body output is received. +At that time ngx_lua can calculate the total length of the body and construct a proper `Content-Length` header to return to the HTTP 1.0 client. +If the `Content-Length` response header is set in the running Lua code, however, this buffering will be disabled even if the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`. -Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." +For large streaming output responses, it is important to disable the [lua_http10_buffering](#lua_http10_buffering) directive to minimise memory usage. -When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. +Note that common HTTP benchmark tools such as `ab` and `http_load` issue HTTP 1.0 requests by default. +To force `curl` to send HTTP 1.0 requests, use the `-0` option. -When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. +[Back to TOC](#table-of-contents) -This directive was first introduced in the `v0.8.5` release. +Statically Linking Pure Lua Modules +=================================== -[Back to TOC](#table-of-contents) +When LuaJIT 2.x is used, it is possible to statically link the bytecode of pure Lua modules into the Nginx executable. -lua_package_path ----------------- +Basically you use the `luajit` executable to compile `.lua` Lua module files to `.o` object files containing the exported bytecode data, and then link the `.o` files directly in your Nginx build. -**syntax:** *lua_package_path <lua-style-path-str>* +Below is a trivial example to demonstrate this. Consider that we have the following `.lua` file named `foo.lua`: -**default:** *The content of LUA_PATH environ variable or Lua's compiled-in defaults.* +```lua -**context:** *http* +-- foo.lua +local _M = {} -Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` -can be used to stand for the original search paths. +function _M.go() + print("Hello from foo") +end -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. +return _M +``` -[Back to TOC](#table-of-contents) +And then we compile this `.lua` file to `foo.o` file: -lua_package_cpath ------------------ + /path/to/luajit/bin/luajit -bg foo.lua foo.o -**syntax:** *lua_package_cpath <lua-style-cpath-str>* +What matters here is the name of the `.lua` file, which determines how you use this module later on the Lua land. The file name `foo.o` does not matter at all except the `.o` file extension (which tells `luajit` what output format is used). If you want to strip the Lua debug information from the resulting bytecode, you can just specify the `-b` option above instead of `-bg`. -**default:** *The content of LUA_CPATH environment variable or Lua's compiled-in defaults.* +Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option to the `./configure` script: -**context:** *http* +```bash -Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` -can be used to stand for the original cpath. +./configure --with-ld-opt="/path/to/foo.o" ... +``` -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. +Finally, you can just do the following in any Lua code run by ngx_lua: -[Back to TOC](#table-of-contents) +```lua -init_by_lua ------------ +local foo = require "foo" +foo.go() +``` -**syntax:** *init_by_lua <lua-script-str>* +And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. -**context:** *http* +If you want to use dot in the Lua module name when calling `require`, as in -**phase:** *loading-config* +```lua -Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. +local foo = require "resty.foo" +``` -When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. +then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. -Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: +It is important to use exactly the same version of LuaJIT when compiling `.lua` files to `.o` files as building nginx + ngx_lua. This is because the LuaJIT bytecode format may be incompatible between different LuaJIT versions. When the bytecode format is incompatible, you will see a Lua runtime error saying that the Lua module is not found. -```nginx +When you have multiple `.lua` files to compile and link, then just specify their `.o` files at the same time in the value of the `--with-ld-opt` option. For instance, -init_by_lua 'cjson = require "cjson"'; +```bash -server { - location = /api { - content_by_lua ' - ngx.say(cjson.encode({dog = 5, cat = 6})) - '; - } -} +./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... ``` -You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: +If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in -```nginx +```bash -lua_shared_dict dogs 1m; +ar rcus libmyluafiles.a *.o +``` -init_by_lua ' - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) -'; +then you can link the `myluafiles` archive as a whole to your nginx executable: -server { - location = /api { - content_by_lua ' - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - '; - } -} +```bash + +./configure \ + --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" ``` -But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. +where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. -Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. +[Back to TOC](#table-of-contents) -Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua_variable_scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). +Data Sharing within an Nginx Worker +=================================== -Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: +To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. -* Logging APIs: [ngx.log](#ngxlog) and [print](#print), -* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). +Here is a complete small example: -More Nginx APIs for Lua may be supported in this context upon future user requests. +```lua -Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase. - -You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the `root` account. +-- mydata.lua +local _M = {} -This directive was first introduced in the `v0.5.5` release. +local data = { + dog = 3, + cat = 4, + pig = 5, +} + +function _M.get_age(name) + return data[name] +end -[Back to TOC](#table-of-contents) +return _M +``` -init_by_lua_file ----------------- +and then accessing it from `nginx.conf`: -**syntax:** *init_by_lua_file <path-to-lua-script-file>* +```nginx -**context:** *http* +location /lua { + content_by_lua ' + local mydata = require "mydata" + ngx.say(mydata.get_age("dog")) + '; +} +``` -**phase:** *loading-config* +The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, +and all subsequent requests to the same nginx worker process will use the reloaded instance of the +module as well as the same copy of the data in it, until a `HUP` signal is sent to the Nginx master process to force a reload. +This data sharing technique is essential for high performance Lua applications based on this module. -Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +Note that this data sharing is on a *per-worker* basis and not on a *per-server* basis. That is, when there are multiple nginx worker processes under an Nginx master, data sharing cannot cross the process boundary between these workers. -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +If server-wide data sharing is required, then use one or more of the following approaches: -This directive was first introduced in the `v0.5.5` release. +1. Use the [ngx.shared.DICT](#ngxshareddict) API provided by this module. +1. Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). +1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The ngx_openresty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. [Back to TOC](#table-of-contents) -init_worker_by_lua ------------------- - -**syntax:** *init_worker_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *starting-worker* - -Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). +Known Issues +============ -This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend healthcheck or other timed routine work. Below is an example, +[Back to TOC](#table-of-contents) -```nginx +TCP socket connect operation issues +----------------------------------- +The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. -init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check +However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end +This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end -'; -``` +[Back to TOC](#table-of-contents) -This directive was first introduced in the `v0.9.5` release. +Lua Coroutine Yielding/Resuming +------------------------------- +* Lua's `dofile` builtin is implemented as a C function in both Lua 5.1 and LuaJIT 2.0/2.1 and when [ngx.location.capture](#ngxlocationcapture) is called, [ngx.exec](#ngxexec), [ngx.exit](#ngxexit) or [ngx.req.read_body](#ngxreqread_body) or similar in the file to be loaded by `dofile`, a coroutine yield across the C function boundary will be initiated. This however is not normally allowed within ngx_lua and will usually result in error messages like `lua handler aborted: runtime error: attempt to yield across C-call boundary`. To avoid this, define a real Lua module and use the Lua `require` builtin instead. +* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. [Back to TOC](#table-of-contents) -init_worker_by_lua_file ------------------------ - -**syntax:** *init_worker_by_lua_file <lua-file-path>* +Lua Variable Scope +------------------ +Care must be taken when importing modules and this form should be used: -**context:** *http* +```lua -**phase:** *starting-worker* +local xxx = require('xxx') +``` -Similar to [init_worker_by_lua](#init_worker_by_lua), but accepts the file path to a Lua source file or Lua bytecode file. +instead of the old deprecated form: -This directive was first introduced in the `v0.9.5` release. +```lua -[Back to TOC](#table-of-contents) +require('xxx') +``` -set_by_lua ----------- +Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the package.loaded table for later reference, and `require()` has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. -**syntax:** *set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]* +Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because -**context:** *server, server if, location, location if* +1. misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, +1. Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and +1. some Lua global variable references are just typos, which are hard to debug. -**phase:** *rewrite* +It's *highly* recommended to always declare them via "local" in the scope that is reasonable. -Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. -The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). +To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: -This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. + $ lua-releng + Checking use of Lua global variables in file lib/foo/bar.lua ... + 1 [1489] SETGLOBAL 7 -1 ; contains + 55 [1506] GETGLOBAL 7 -3 ; setvar + 3 [1545] GETGLOBAL 3 -4 ; varexpand -This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. +The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. -At least the following API functions are currently disabled within the context of `set_by_lua`: +This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data_sharing_within_an_nginx_worker) for the reasons behind this. -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). -* Sleeping API function [ngx.sleep](#ngxsleep). +[Back to TOC](#table-of-contents) -In addition, note that this directive can only write out a value to a single Nginx variable at -a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. +Locations Configured by Subrequest Directives of Other Modules +-------------------------------------------------------------- +The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. ```nginx location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally + content_by_lua ' + res = ngx.location.capture("/bar") '; - - echo "sum = $sum, diff = $diff"; +} +location /bar { + echo_location /blah; +} +location /blah { + echo "Success!"; } ``` -This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. - ```nginx -set $foo 32; -set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; -set $baz "bar: $bar"; # $baz == "bar: 33" +$ curl -i http://example.com/foo ``` -As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. - -This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. +will not work as expected. [Back to TOC](#table-of-contents) -set_by_lua_file ---------------- -**syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* +Special PCRE Sequences +---------------------- +PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: -**phase:** *rewrite* +```nginx -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +# nginx.conf +? location /test { +? content_by_lua ' +? local regex = "\d+" -- THIS IS WRONG!! +? local m = ngx.re.match("hello, 1234", regex) +? if m then ngx.say(m[0]) else ngx.say("not matched!") end +? '; +? } +# evaluates to "not matched!" +``` -Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. +To avoid this, *double* escape the backslash: -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +```nginx -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +# nginx.conf +location /test { + content_by_lua ' + local regex = "\\\\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; +} +# evaluates to "1234" +``` -This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. +Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. -[Back to TOC](#table-of-contents) +Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. -content_by_lua --------------- +```nginx -**syntax:** *content_by_lua <lua-script-str>* +# nginx.conf +location /test { + content_by_lua ' + local regex = [[\\d+]] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; +} +# evaluates to "1234" +``` -**context:** *location, location if* +Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. -**phase:** *content* +Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. +The `[=[...]=]` form may be used as the default form if desired. -Acts as a "content handler" and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). +```nginx -Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. +# nginx.conf +location /test { + content_by_lua ' + local regex = [=[[0-9]+]=] + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + '; +} +# evaluates to "1234" +``` -[Back to TOC](#table-of-contents) +An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. +With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. -content_by_lua_file -------------------- +```lua -**syntax:** *content_by_lua_file <path-to-lua-script-file>* - -**context:** *location, location if* +-- test.lua +local regex = "\\d+" +local m = ngx.re.match("hello, 1234", regex) +if m then ngx.say(m[0]) else ngx.say("not matched!") end +-- evaluates to "1234" +``` -**phase:** *content* +Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. + +```lua -Equivalent to [content_by_lua](#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +-- test.lua +local regex = [[\d+]] +local m = ngx.re.match("hello, 1234", regex) +if m then ngx.say(m[0]) else ngx.say("not matched!") end +-- evaluates to "1234" +``` -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. +[Back to TOC](#table-of-contents) -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +Mixing with SSI Not Supported +----------------------------- -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. [Back to TOC](#table-of-contents) -rewrite_by_lua --------------- +SPDY Mode Not Fully Supported +----------------------------- -**syntax:** *rewrite_by_lua <lua-script-str>* +Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), and [ngx.req.socket](#ngxreqsocket). -**context:** *http, server, location, location if* +[Back to TOC](#table-of-contents) -**phase:** *rewrite tail* +TODO +==== -Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). +[Back to TOC](#table-of-contents) -Note that this handler always runs *after* the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html). So the following will work as expected: +Short Term +---------- +* implement the SSL cosocket API. +* review and apply Jader H. Silva's patch for `ngx.re.split()`. +* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option +* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. +* add configure options for different strategies of handling the cosocket connection exceeding in the pools. +* add directives to run Lua codes when nginx stops. +* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. -```nginx +[Back to TOC](#table-of-contents) -location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; -} -``` +Longer Term +----------- +* add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. +* add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). +[Back to TOC](#table-of-contents) -On the other hand, the following will not work as expected: +Changes +======= -```nginx +The changes of every release of this module can be obtained from the ngx_openresty bundle's change logs: -? location /foo { -? set $a 12; # create and initialize $a -? set $b ''; # create and initialize $b -? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; -? if ($b = '13') { -? rewrite ^ /bar redirect; -? break; -? } -? -? echo "res = $b"; -? } -``` + -because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. +[Back to TOC](#table-of-contents) -The right way of doing this is as follows: +Test Suite +========== -```nginx +The following dependencies are required to run the test suite: -location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; -} -``` +* Nginx version >= 1.4.2 -Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, +* Perl modules: + * Test::Nginx: -```nginx +* Nginx modules: + * [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) + * [ngx_set_misc](http://github.com/openresty/set-misc-nginx-module) + * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. + * [ngx_echo](http://github.com/openresty/echo-nginx-module) + * [ngx_memc](http://github.com/openresty/memc-nginx-module) + * [ngx_srcache](http://github.com/openresty/srcache-nginx-module) + * ngx_lua (i.e., this module) + * [ngx_lua_upstream](http://github.com/openresty/lua-upstream-nginx-module) + * [ngx_headers_more](http://github.com/openresty/headers-more-nginx-module) + * [ngx_drizzle](http://github.com/openresty/drizzle-nginx-module) + * [ngx_rds_json](http://github.com/openresty/rds-json-nginx-module) + * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) + * [ngx_redis2](http://github.com/openresty/redis2-nginx-module) -location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; -} -``` +The order in which these modules are added during configuration is important because the position of any filter module in the +filtering chain determines the final output, for example. The correct adding order is shown above. -can be implemented in ngx_lua as: +* 3rd-party Lua libraries: + * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) -```nginx +* Applications: + * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' + * memcached: listening on the default port, 11211. + * redis: listening on the default port, 6379. -location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; -} - -location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; -} -``` +See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build2.sh) for more details on setting up the testing environment. -Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. +To run the whole test suite in the default testing mode: -Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](#rewrite_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib -r t -If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, -```nginx +To run specific test files: -location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; -} -location /bar { - ... -} -``` + cd /path/to/lua-nginx-module + export PATH=/path/to/your/nginx/sbin:$PATH + prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t -Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. -The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. +To run a specific test block in a particular test file, add the line `--- ONLY` to the test block you want to run, and then use the `prove` utility to run that `.t` file. + +There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [Test::Nginx documentation](http://search.cpan.org/perldoc?Test::Nginx) for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: [Back to TOC](#table-of-contents) -rewrite_by_lua_file -------------------- +Copyright and License +===================== -**syntax:** *rewrite_by_lua_file <path-to-lua-script-file>* +This module is licensed under the BSD license. -**context:** *http, server, location, location if* +Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . -**phase:** *rewrite tail* +Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. -Equivalent to [rewrite_by_lua](#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +All rights reserved. -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) -access_by_lua -------------- +See Also +======== -**syntax:** *access_by_lua <lua-script-str>* +* [lua-resty-memcached](http://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. +* [lua-resty-redis](http://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. +* [lua-resty-mysql](http://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. +* [lua-resty-upload](http://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. +* [lua-resty-dns](http://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. +* [lua-resty-websocket](http://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. +* [lua-resty-string](http://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). +* [lua-resty-lock](http://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. +* [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) +* [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) +* [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) +* [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) +* [ngx_devel_kit](http://github.com/simpl/ngx_devel_kit) +* [echo-nginx-module](http://github.com/openresty/echo-nginx-module) +* [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) +* [postgres-nginx-module](http://github.com/FRiCKLE/ngx_postgres) +* [memc-nginx-module](http://github.com/openresty/memc-nginx-module) +* [The ngx_openresty bundle](http://openresty.org) +* [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) -**context:** *http, server, location, location if* +[Back to TOC](#table-of-contents) -**phase:** *access tail* +Directives +========== -Acts as an access phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). + -Note that this handler always runs *after* the standard [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html). So the following will work as expected: +[Back to TOC](#table-of-contents) -```nginx +lua_use_default_type +-------------------- +**syntax:** *lua_use_default_type on | off* -location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... -} -``` +**default:** *lua_use_default_type on* -That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). +**context:** *http, server, location, location if* -Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](#access_by_lua): +Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. If you do not want a default `Content-Type` response header for your Lua request handlers, then turn this directive off. -```nginx +This directive is turned on by default. -location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} -``` +This directive was first introduced in the `v0.9.1` release. -can be implemented in ngx_lua as: +[Back to TOC](#table-of-contents) -```nginx +lua_code_cache +-------------- +**syntax:** *lua_code_cache on | off* -location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... -} -``` +**default:** *lua_code_cache on* -As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. +**context:** *http, server, location, location if* -Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. +Enables or disables the Lua code cache for Lua code in `*_by_lua_file` directives (like [set_by_lua_file](#set_by_lua_file) and +[content_by_lua_file](#content_by_lua_file)) and Lua modules. -[Back to TOC](#table-of-contents) +When turning off, every request served by ngx_lua will run in a separate Lua VM instance, starting from the `0.9.3` release. So the Lua files referenced in [set_by_lua_file](#set_by_lua_file), +[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), +and etc will not be cached +and all Lua modules used will be loaded from scratch. With this in place, developers can adopt an edit-and-refresh approach. -access_by_lua_file ------------------- +Please note however, that Lua code written inlined within nginx.conf +such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), +[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will not be updated when you edit the inlined Lua code in your `nginx.conf` file because only the Nginx config file parser can correctly parse the `nginx.conf` +file and the only way is to reload the config file +by sending a `HUP` signal or just to restart Nginx. -**syntax:** *access_by_lua_file <path-to-lua-script-file>* +Even when the code cache is enabled, Lua files which are loaded by `dofile` or `loadfile` +in *_by_lua_file cannot be cached (unless you cache the results yourself). Usually you can either use the [init_by_lua](#init_by_lua) +or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules +and load them via `require`. -**context:** *http, server, location, location if* +The ngx_lua module does not support the `stat` mode available with the +Apache `mod_lua` module (yet). -**phase:** *access tail* +Disabling the Lua code cache is strongly +discouraged for production use and should only be used during +development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. -Equivalent to [access_by_lua](#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +[Back to TOC](#table-of-contents) -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. +lua_regex_cache_max_entries +--------------------------- +**syntax:** *lua_regex_cache_max_entries <num>* -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +**default:** *lua_regex_cache_max_entries 1024* -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. +**context:** *http* -[Back to TOC](#table-of-contents) +Specifies the maximum number of entries allowed in the worker process level compiled regex cache. -header_filter_by_lua --------------------- +The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. -**syntax:** *header_filter_by_lua <lua-script-str>* +The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: -**context:** *http, server, location, location if* -**phase:** *output-header-filter* + 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... -Uses Lua code specified in `` to define an output header filter. -Note that the following API functions are currently disabled within this context: +Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). +[Back to TOC](#table-of-contents) -Here is an example of overriding a response header (or adding one if absent) in our Lua header filter: +lua_regex_match_limit +--------------------- +**syntax:** *lua_regex_match_limit <num>* -```nginx +**default:** *lua_regex_match_limit 0* -location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; -} -``` +**context:** *http* -This directive was first introduced in the `v0.2.1rc20` release. +Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." -[Back to TOC](#table-of-contents) +When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. -header_filter_by_lua_file -------------------------- +When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. -**syntax:** *header_filter_by_lua_file <path-to-lua-script-file>* +This directive was first introduced in the `v0.8.5` release. -**context:** *http, server, location, location if* +[Back to TOC](#table-of-contents) -**phase:** *output-header-filter* +lua_package_path +---------------- -Equivalent to [header_filter_by_lua](#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +**syntax:** *lua_package_path <lua-style-path-str>* -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +**default:** *The content of LUA_PATH environ variable or Lua's compiled-in defaults.* -This directive was first introduced in the `v0.2.1rc20` release. +**context:** *http* + +Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), +[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` +can be used to stand for the original search paths. + +As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. [Back to TOC](#table-of-contents) -body_filter_by_lua ------------------- +lua_package_cpath +----------------- -**syntax:** *body_filter_by_lua <lua-script-str>* +**syntax:** *lua_package_cpath <lua-style-cpath-str>* -**context:** *http, server, location, location if* +**default:** *The content of LUA_CPATH environment variable or Lua's compiled-in defaults.* -**phase:** *output-body-filter* +**context:** *http* -Uses Lua code specified in `` to define an output body filter. +Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), +[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` +can be used to stand for the original cpath. -The input data chunk is passed via [ngx.arg](#ngxarg)[1] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)[2] (as a Lua boolean value). +As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. -Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) +[Back to TOC](#table-of-contents) -The output data stream can be aborted immediately by running the following Lua statement: +init_by_lua +----------- -```lua +**syntax:** *init_by_lua <lua-script-str>* -return ngx.ERROR -``` +**context:** *http* -This will truncate the response body and usually result in incomplete and also invalid responses. +**phase:** *loading-config* -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)[1] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: +Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. + +When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. + +Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: ```nginx -location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; +init_by_lua 'cjson = require "cjson"'; + +server { + location = /api { + content_by_lua ' + ngx.say(cjson.encode({dog = 5, cat = 6})) + '; + } } ``` -When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. - -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)[2]. For example, +You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: ```nginx -location /t { - echo hello world; - echo hiya globe; +lua_shared_dict dogs 1m; - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end +init_by_lua ' + local dogs = ngx.shared.dogs; + dogs:set("Tom", 56) +'; - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; +server { + location = /api { + content_by_lua ' + local dogs = ngx.shared.dogs; + ngx.say(dogs:get("Tom")) + '; + } } ``` -Then `GET /t` will just return the output +But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. +Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. - hello world +Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua_variable_scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). +Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: -That is, when the body filter sees a chunk containing the word "hello", then it will set the "eof" flag to true immediately, resulting in truncated but still valid responses. +* Logging APIs: [ngx.log](#ngxlog) and [print](#print), +* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). -When the Lua code may change the length of the response body, then it is required to always clear out the `Content-Length` response header (if any) in a header filter to enforce streaming output, as in +More Nginx APIs for Lua may be supported in this context upon future user requests. -```nginx +Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase. -location /foo { - # fastcgi_pass/proxy_pass/... +You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the `root` account. - header_filter_by_lua 'ngx.header.content_length = nil'; - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; -} -``` +This directive was first introduced in the `v0.5.5` release. -Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: +[Back to TOC](#table-of-contents) -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). +init_by_lua_file +---------------- -Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request. +**syntax:** *init_by_lua_file <path-to-lua-script-file>* -This directive was first introduced in the `v0.5.0rc32` release. +**context:** *http* -[Back to TOC](#table-of-contents) +**phase:** *loading-config* -body_filter_by_lua_file ------------------------ +Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. -**syntax:** *body_filter_by_lua_file <path-to-lua-script-file>* +When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Equivalent to [body_filter_by_lua](#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc32` release. +This directive was first introduced in the `v0.5.5` release. [Back to TOC](#table-of-contents) -log_by_lua ----------- - -**syntax:** *log_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* +init_worker_by_lua +------------------ -**phase:** *log* +**syntax:** *init_worker_by_lua <lua-script-str>* -Run the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs after. +**context:** *http* -Note that the following API functions are currently disabled within this context: +**phase:** *starting-worker* -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). +Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). -Here is an example of gathering average data for [$upstream_response_time](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_response_time): +This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend healthcheck or other timed routine work. Below is an example, ```nginx -lua_shared_dict log_dict 5M; - -server { - location / { - proxy_pass http://mybackend; - - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) - - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) +init_worker_by_lua ' + local delay = 3 -- in seconds + local new_timer = ngx.timer.at + local log = ngx.log + local ERR = ngx.ERR + local check - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) + check = function(premature) + if not premature then + -- do the health check or other routine work + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return end - '; - } - - location = /status { - content_by_lua ' - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") + end + end - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - '; - } -} + local ok, err = new_timer(delay, check) + if not ok then + log(ERR, "failed to create timer: ", err) + return + end +'; ``` -This directive was first introduced in the `v0.5.0rc31` release. +This directive was first introduced in the `v0.9.5` release. [Back to TOC](#table-of-contents) -log_by_lua_file ---------------- - -**syntax:** *log_by_lua_file <path-to-lua-script-file>* +init_worker_by_lua_file +----------------------- -**context:** *http, server, location, location if* +**syntax:** *init_worker_by_lua_file <lua-file-path>* -**phase:** *log* +**context:** *http* -Equivalent to [log_by_lua](#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +**phase:** *starting-worker* -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. +Similar to [init_worker_by_lua](#init_worker_by_lua), but accepts the file path to a Lua source file or Lua bytecode file. -This directive was first introduced in the `v0.5.0rc31` release. +This directive was first introduced in the `v0.9.5` release. [Back to TOC](#table-of-contents) -lua_need_request_body ---------------------- - -**syntax:** *lua_need_request_body <on|off>* - -**default:** *off* - -**context:** *main | server | location* - -**phase:** *depends on usage* - -Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. - -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, -[client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. +set_by_lua +---------- -If the current location includes [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) directives, -then the request body will be read just before the [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code is run (and also at the -`rewrite` phase). Similarly, if only [content_by_lua](#content_by_lua) is specified, -the request body will not be read until the content handler's Lua code is -about to run (i.e., the request body will be read during the content phase). +**syntax:** *set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]* -It is recommended however, to use the [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body) functions for finer control over the request body reading process instead. +**context:** *server, server if, location, location if* -This also applies to [access_by_lua](#access_by_lua) and [access_by_lua_file](#access_by_lua_file). +**phase:** *rewrite* -[Back to TOC](#table-of-contents) +Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. +The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). -lua_shared_dict ---------------- +This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. -**syntax:** *lua_shared_dict <name> <size>* +This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. -**default:** *no* +At least the following API functions are currently disabled within the context of `set_by_lua`: -**context:** *http* +* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) +* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). +* Sleeping API function [ngx.sleep](#ngxsleep). -**phase:** *depends on usage* +In addition, note that this directive can only write out a value to a single Nginx variable at +a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. -Declares a shared memory zone, ``, to serve as storage for the shm based Lua dictionary `ngx.shared.`. +```nginx -Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. +location /foo { + set $diff ''; # we have to predefine the $diff variable here + + set_by_lua $sum ' + local a = 32 + local b = 56 + + ngx.var.diff = a - b; -- write to $diff directly + return a + b; -- return the $sum value normally + '; + + echo "sum = $sum, diff = $diff"; +} +``` -The `` argument accepts size units such as `k` and `m`: +This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. ```nginx -http { - lua_shared_dict dogs 10m; - ... -} +set $foo 32; +set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; +set $baz "bar: $bar"; # $baz == "bar: 33" ``` -See [ngx.shared.DICT](#ngxshareddict) for details. +As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. -This directive was first introduced in the `v0.3.1rc22` release. +This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. [Back to TOC](#table-of-contents) -lua_socket_connect_timeout --------------------------- +set_by_lua_file +--------------- +**syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* -**syntax:** *lua_socket_connect_timeout <time>* +**context:** *server, server if, location, location if* -**default:** *lua_socket_connect_timeout 60s* +**phase:** *rewrite* -**context:** *http, server, location* +Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. -This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](#tcpsockconnect) method and can be overridden by the [settimeout](#tcpsocksettimeout) method. +Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. -The `