From f9dc0dc01d1a65fa84fd3ef46b6aebdf7884a5d7 Mon Sep 17 00:00:00 2001 From: jinglong Date: Mon, 13 Aug 2012 14:57:58 +0800 Subject: [PATCH 0001/2239] fix strict-aliasing warnings in ngx_http_lua_clfactory_bytecode_prepare --- src/ngx_http_lua_clfactory.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index fc3e511c61..7465e2bdaf 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -283,8 +283,9 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, { int x = 1, size_of_int, size_of_size_t, little_endian, size_of_inst, version, stripped; - size_t size, bytecode_len; + 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; serr = NULL; @@ -404,12 +405,13 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, goto error; } - /* source string length */ - *(size_t *) (lf->begin_code.str + POS_SOURCE_STR_LEN) = 0; - /* start line */ - *(int *) (lf->begin_code.str + POS_START_LINE) = 0; - /* last line */ - *(int *) (lf->begin_code.str + POS_LAST_LINE) = 0; + /* clear the following fields to zero: + * - source string length + * - start line + * - last line + */ + ngx_memzero(lf->begin_code.str + POS_SOURCE_STR_LEN, + sizeof(size_t) + sizeof(int) * 2); /* number of upvalues */ *(lf->begin_code.str + POS_NUM_OF_UPVS) = 0; /* number of paramters */ @@ -419,7 +421,8 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, /* max stack size */ *(lf->begin_code.str + POS_MAX_STACK_SIZE) = 2; /* number of bytecode instructions */ - *(int *) (lf->begin_code.str + POS_NUM_OF_INST) = 3; + ngx_memcpy(lf->begin_code.str + POS_NUM_OF_INST, &num_of_inst, + sizeof(int)); lf->begin_code_len = POS_BYTECODE; @@ -448,10 +451,11 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, ngx_memcpy(lf->begin_code.str + POS_BYTECODE, bytecode, bytecode_len); /* number of consts */ - *(int *) (lf->begin_code.str + POS_BYTECODE + bytecode_len) = 0; + ngx_memzero(lf->begin_code.str + POS_BYTECODE + bytecode_len, + sizeof(int)); /* number of internal functions */ - *(int *) (lf->begin_code.str + POS_BYTECODE + bytecode_len - + sizeof(int)) = 1; + ngx_memcpy(lf->begin_code.str + POS_BYTECODE + bytecode_len + + sizeof(int), &num_of_inter_func, sizeof(int)); lf->begin_code_len += bytecode_len + sizeof(int) + sizeof(int); From 5cb6e9fa526816cbdc4894d4322c8a2d7a286241 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 28 Aug 2012 16:04:08 -0700 Subject: [PATCH 0002/2239] refactor: now every lua coroutine takes its own context state for its nginx-side activities. bugfix: coroutine.status() returned "suspended" for "normal" coroutines. bugfix: coroutine.resume() did not return an error immediately when operating on "normal" coroutines. feature: added new dtrace static probes http-lua-user-coroutine-yield and http-lua-entry-coroutine-yield. --- dtrace/ngx_lua_provider.d | 4 + src/ngx_http_lua_accessby.c | 4 +- src/ngx_http_lua_bodyfilterby.c | 2 - src/ngx_http_lua_capturefilter.c | 19 +- src/ngx_http_lua_common.h | 118 ++++++++---- src/ngx_http_lua_contentby.c | 2 + src/ngx_http_lua_coroutine.c | 137 ++++++++++---- src/ngx_http_lua_coroutine.h | 5 - src/ngx_http_lua_headerfilterby.c | 2 - src/ngx_http_lua_output.c | 8 +- src/ngx_http_lua_probe.h | 8 + src/ngx_http_lua_req_body.c | 11 +- src/ngx_http_lua_rewriteby.c | 2 + src/ngx_http_lua_sleep.c | 54 +++++- src/ngx_http_lua_socket_tcp.c | 101 +++++++--- src/ngx_http_lua_socket_udp.c | 45 +++-- src/ngx_http_lua_subrequest.c | 122 +++++++----- src/ngx_http_lua_subrequest.h | 7 + src/ngx_http_lua_util.c | 299 ++++++++++++++++-------------- src/ngx_http_lua_util.h | 6 + t/014-bugs.t | 3 + t/017-exec.t | 6 +- t/020-subrequest.t | 4 +- t/061-lua-redis.t | 82 +++++++- t/091-coroutine.t | 74 +++++--- valgrind.suppress | 11 +- 26 files changed, 784 insertions(+), 352 deletions(-) diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index 7e2bc1aac1..fa1411f1aa 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -6,6 +6,10 @@ provider nginx_lua { void *parent, void *child); probe http__lua__user__coroutine__resume(ngx_http_request_t *r, void *parent, void *child); + probe http__lua__user__coroutine__yield(ngx_http_request_t *r, + void *parent, void *child); + probe http__lua__entry__coroutine__yield(ngx_http_request_t *r, + void *L); }; diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index b71a095494..c3ea63fdfc 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -140,8 +140,6 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; - dd("HERE"); - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -265,6 +263,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entry_co = co; ctx->cur_co = co; + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; /* }}} */ diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 75176d5319..c62aedfcff 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -156,8 +156,6 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_lua_loc_conf_t *llcf; char *err; - dd("HERE"); - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index 9dca7bcbd0..a98a1b60ff 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -38,10 +38,12 @@ ngx_http_lua_capture_filter_init(ngx_conf_t *cf) static ngx_int_t ngx_http_lua_capture_header_filter(ngx_http_request_t *r) { - ngx_http_post_subrequest_t *ps; + ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *old_ctx; ngx_http_lua_ctx_t *ctx; + ngx_http_lua_post_subrequest_data_t *psr_data; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua capture header filter, uri \"%V\"", &r->uri); @@ -50,14 +52,19 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) dd("old ctx: %p", ctx); if (ctx == NULL || ! ctx->capture) { - ps = r->post_subrequest; - if (ps != NULL && ps->handler == ngx_http_lua_post_subrequest && - ps->data != NULL) + + psr = r->post_subrequest; + + if (psr != NULL + && psr->handler == ngx_http_lua_post_subrequest + && psr->data != NULL) { /* the lua ctx has been cleared by ngx_http_internal_redirect, * resume it from the post_subrequest data */ - old_ctx = ps->data; + psr_data = psr->data; + + old_ctx = psr_data->ctx; if (ctx == NULL) { ctx = old_ctx; @@ -70,7 +77,7 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) ctx->capture = old_ctx->capture; ctx->index = old_ctx->index; - ps->data = ctx; + psr_data->ctx = ctx; } } } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 8bb90f43c6..e8e828fd15 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -196,9 +196,57 @@ typedef enum { } ngx_http_lua_user_coro_op_t; -typedef struct { +typedef enum { + NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */ + NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */ + NGX_HTTP_LUA_CO_NORMAL = 2, /* coroutine normal */ + NGX_HTTP_LUA_CO_DEAD = 3, /* coroutine dead */ +} ngx_http_lua_co_status_t; + + +typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; + + +struct ngx_http_lua_co_ctx_s { void *data; /* user state for cosockets */ + lua_State *co; + ngx_http_lua_co_ctx_t *parent_co_ctx; + + ngx_http_lua_co_status_t co_status; + + ngx_http_cleanup_pt *cleanup; + + unsigned nsubreqs; /* number of subrequests of the + * current request */ + + ngx_int_t *sr_statuses; /* all capture subrequest statuses */ + + ngx_http_headers_out_t **sr_headers; + + ngx_str_t *sr_bodies; /* all captured subrequest bodies */ + + unsigned waiting; /* number of subrequests being + waited */ + + ngx_event_t sleep; /* used for ngx.sleep */ + + unsigned done:1; /* 1: subrequest is just done; + 0: subrequest is not done + yet or has already done */ + + unsigned waiting_flush:1; /* for ngx.flush() */ + + unsigned socket_busy:1; /* for TCP */ + unsigned socket_ready:1; /* for TCP */ + + unsigned udp_socket_busy:1; /* for UDP */ + unsigned udp_socket_ready:1; /* for UDP */ + +}; + + +typedef struct ngx_http_lua_ctx_s { uint8_t context; /* the current running directive context (or running phase) for the current Lua chunk */ @@ -207,8 +255,17 @@ typedef struct { not necessarily to be the request's entry coroutine */ + ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ + + lua_State *entry_co; /* the entry Lua coroutine */ + /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ + ngx_array_t *user_co_ctx; /* coroutine contexts for user + coroutines */ + + ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the + entry coroutine */ int entry_ref; /* reference to anchor the entry coroutine in the lua registry, @@ -228,30 +285,32 @@ typedef struct { ngx_http_cleanup_pt *cleanup; - ngx_chain_t *body; /* buffered response body chains */ + ngx_chain_t *body; /* buffered subrequest response body + chains */ - unsigned nsubreqs; /* number of subrequests of the - * current request */ + ngx_str_t exec_uri; + ngx_str_t exec_args; - ngx_int_t *sr_statuses; /* all capture subrequest statuses */ - - ngx_http_headers_out_t **sr_headers; + ngx_int_t exit_code; - ngx_str_t *sr_bodies; /* all captured subrequest bodies */ + ngx_http_lua_co_ctx_t *req_body_reader_co_ctx; /* co ctx for the coroutine + reading the request + body */ ngx_uint_t index; /* index of the current subrequest in its parent request */ - unsigned waiting; /* number of subrequests being - waited */ + unsigned run_post_subrequest:1; /* whether it has run + post_subrequest + (for subrequests only) */ - ngx_str_t exec_uri; - ngx_str_t exec_args; + unsigned req_read_body_done:1; /* used by + ngx.req.read_body */ - ngx_int_t exit_code; - - ngx_event_t sleep; /* used for ngx.sleep */ + unsigned waiting_more_body:1; /* 1: waiting for more + request body data; + 0: no need to wait */ ngx_http_lua_user_coro_op_t co_op:2; /* coroutine API operation */ @@ -263,39 +322,24 @@ typedef struct { unsigned eof:1; /* 1: last_buf has been sent; 0: last_buf not sent yet */ - unsigned done:1; /* 1: subrequest is just done; - 0: subrequest is not done - yet or has already done */ + unsigned capture:1; /* 1: response body of current request + is to be captured by the lua + capture filter, + 0: not to be captured */ - unsigned capture:1; /* 1: body of current request is - to be captured; - 0: not captured */ unsigned read_body_done:1; /* 1: request body has been all read; 0: body has not been all read */ - unsigned waiting_more_body:1; /* 1: waiting for more data; - 0: no need to wait */ - unsigned req_read_body_done:1; /* used by ngx.req.read_body */ + unsigned headers_set:1; /* whether the user has set custom + response headers */ - unsigned headers_set:1; unsigned entered_rewrite_phase:1; unsigned entered_access_phase:1; unsigned entered_content_phase:1; - /* whether it has run post_subrequest */ - unsigned run_post_subrequest:1; - - unsigned waiting_flush:1; - - unsigned socket_busy:1; /* for TCP */ - unsigned socket_ready:1; /* for TCP */ - - unsigned udp_socket_busy:1; /* for UDP */ - unsigned udp_socket_ready:1; /* for UDP */ - - unsigned buffering:1; + unsigned buffering:1; /* HTTP 1.0 response body buffering flag */ } ngx_http_lua_ctx_t; diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 0854772c8a..a271ffeed8 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -72,6 +72,8 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entry_co = co; ctx->cur_co = co; + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; /* {{{ register request cleanup hooks */ diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 3f4de76542..6a0815a43c 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -20,9 +20,11 @@ static int ngx_http_lua_coroutine_create(lua_State *L); static int ngx_http_lua_coroutine_resume(lua_State *L); static int ngx_http_lua_coroutine_yield(lua_State *L); +static int ngx_http_lua_coroutine_status(lua_State *L); -static char ngx_http_lua_orig_co_status_key; +static const char * ngx_http_lua_co_status_names[] = + {"running", "suspended", "normal", "dead"}; static int @@ -33,8 +35,7 @@ ngx_http_lua_coroutine_create(lua_State *L) ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_ctx_t *ctx; - - /* L is the current thread */ + ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); @@ -67,6 +68,14 @@ ngx_http_lua_coroutine_create(lua_State *L) ngx_http_lua_probe_user_coroutine_create(r, L, co); + coctx = ngx_http_lua_create_co_ctx(r, ctx); + if (coctx == NULL) { + return luaL_error(L, "out of memory"); + } + + coctx->co = co; + coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; + /* make new coroutine share globals of the parent coroutine. * NOTE: globals don't have to be separated! */ lua_pushvalue(L, LUA_GLOBALSINDEX); @@ -85,11 +94,11 @@ ngx_http_lua_coroutine_create(lua_State *L) static int ngx_http_lua_coroutine_resume(lua_State *L) { - ngx_str_t status = ngx_null_string; - lua_State *co, *mt; + lua_State *co; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_co_ctx_t *p_coctx; /* parent co ctx */ co = lua_tothread(L, 1); @@ -113,48 +122,41 @@ ngx_http_lua_coroutine_resume(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - lua_pushlightuserdata(L, &ngx_http_lua_orig_co_status_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushvalue(L, 1); - lua_call(L, 1, 1); + p_coctx = ctx->cur_co_ctx; + if (p_coctx == NULL) { + return luaL_error(L, "no parent co ctx found"); + } - status.data = (u_char *) lua_tolstring(L, -1, &status.len); + coctx = ngx_http_lua_get_co_ctx(co, ctx); + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } - dd("co status: %s", status.data); + ngx_http_lua_probe_user_coroutine_resume(r, L, co); - /* TODO we should reject resuming logically "normal" coroutines here - * as well */ + if (coctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) { + dd("coroutine resume: %d", coctx->co_status); - if (status.len != sizeof("suspended") - 1) { lua_pushboolean(L, 0); lua_pushfstring(L, "cannot resume %s coroutine", - status.data ? (char *) status.data : "unknown"); + ngx_http_lua_co_status_names[coctx->co_status]); return 2; } - lua_pop(L, 1); /* remove the status string */ + p_coctx->co_status = NGX_HTTP_LUA_CO_NORMAL; - ngx_http_lua_probe_user_coroutine_resume(r, L, co); + coctx->parent_co_ctx = p_coctx; - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); - mt = lmcf->lua; - - /* record parent-child relationship */ - - ngx_http_lua_get_coroutine_parents(mt); - - lua_pushthread(co); /* key: child coroutine */ - lua_xmove(co, mt, 1); - lua_pushthread(L); /* val: parent coroutine */ - lua_xmove(L, mt, 1); - lua_rawset(mt, -3); - lua_pop(mt, 1); + dd("set coroutine to running"); + coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ctx->co_op = NGX_HTTP_LUA_USER_CORO_RESUME; + ctx->cur_co_ctx = coctx; + ctx->cur_co = co; /* yield and pass args to main thread, and resume target coroutine from * there */ - return lua_yield(L, lua_gettop(L)); + return lua_yield(L, lua_gettop(L) - 1); } @@ -163,6 +165,7 @@ ngx_http_lua_coroutine_yield(lua_State *L) { ngx_http_request_t *r; 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); @@ -184,6 +187,20 @@ ngx_http_lua_coroutine_yield(lua_State *L) ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD; + coctx = ctx->cur_co_ctx; + + coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; + + if (coctx->parent_co_ctx) { + dd("set coroutine to running"); + coctx->parent_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + + ngx_http_lua_probe_user_coroutine_yield(r, coctx->parent_co_ctx->co, L); + + } else { + ngx_http_lua_probe_user_coroutine_yield(r, NULL, L); + } + /* yield and pass retvals to main thread, * and resume parent coroutine there */ return lua_yield(L, lua_gettop(L)); @@ -205,25 +222,21 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) lua_getfield(L, -1, "running"); lua_setfield(L, -3, "running"); - /* set status to the old one */ - lua_getfield(L, -1, "status"); - lua_setfield(L, -3, "status"); - - /* save coroutine.status to registry */ - lua_pushlightuserdata(L, &ngx_http_lua_orig_co_status_key); - lua_getfield(L, -2, "status"); - lua_rawset(L, LUA_REGISTRYINDEX); - /* pop the old coroutine */ lua_pop(L, 1); lua_pushcfunction(L, ngx_http_lua_coroutine_create); lua_setfield(L, -2, "create"); + lua_pushcfunction(L, ngx_http_lua_coroutine_resume); lua_setfield(L, -2, "resume"); + lua_pushcfunction(L, ngx_http_lua_coroutine_yield); lua_setfield(L, -2, "yield"); + lua_pushcfunction(L, ngx_http_lua_coroutine_status); + lua_setfield(L, -2, "status"); + lua_setglobal(L, "coroutine"); /* inject wrap */ @@ -256,3 +269,45 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) } } + +static int +ngx_http_lua_coroutine_status(lua_State *L) +{ + lua_State *co; /* new coroutine to be created */ + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ + + co = lua_tothread(L, 1); + + 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); + + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + 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); + + coctx = ngx_http_lua_get_co_ctx(co, ctx); + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + + dd("co status: %d", coctx->co_status); + + lua_pushstring(L, ngx_http_lua_co_status_names[coctx->co_status]); + return 1; +} + diff --git a/src/ngx_http_lua_coroutine.h b/src/ngx_http_lua_coroutine.h index c7d6741f03..b599d57b09 100644 --- a/src/ngx_http_lua_coroutine.h +++ b/src/ngx_http_lua_coroutine.h @@ -7,11 +7,6 @@ #include "ngx_http_lua_common.h" -#define ngx_http_lua_get_coroutine_parents(L) \ - lua_pushlightuserdata(L, &ngx_http_lua_coroutine_parents_key); \ - lua_rawget(L, LUA_REGISTRYINDEX); - - void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L); int ngx_http_lua_resume(lua_State *L, int nargs); diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index e995cced85..b6bf61ea7e 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -143,8 +143,6 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; char *err; - dd("HERE"); - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index 78a9df8bb4..fe1c632914 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -459,6 +459,7 @@ ngx_http_lua_ngx_flush(lua_State *L) unsigned wait = 0; ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; + ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n > 1) { @@ -485,6 +486,11 @@ ngx_http_lua_ngx_flush(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + coctx = ctx->cur_co_ctx; + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + if (r->header_only) { return 0; } @@ -537,7 +543,7 @@ ngx_http_lua_ngx_flush(lua_State *L) "lua flush requires waiting: buffered 0x%uxd", (int) r->connection->buffered); - ctx->waiting_flush = 1; + coctx->waiting_flush = 1; if (ctx->entered_content_phase) { /* mimic ngx_http_set_write_handler */ diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index 62b51e9785..d319933436 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -29,12 +29,20 @@ #define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) \ NGINX_LUA_HTTP_LUA_USER_COROUTINE_RESUME(r, parent, child) +#define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) \ + NGINX_LUA_HTTP_LUA_USER_COROUTINE_YIELD(r, parent, child) + +#define ngx_http_lua_probe_entry_coroutine_yield(r, L) \ + NGINX_LUA_HTTP_LUA_ENTRY_COROUTINE_YIELD(r, L) + #else /* !(NGX_DTRACE) */ #define ngx_http_lua_probe_register_preload_package(L, pkg) #define ngx_http_lua_probe_req_socket_consume_preread(r, data, len) #define ngx_http_lua_probe_user_coroutine_create(r, parent, child) #define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) +#define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) +#define ngx_http_lua_probe_entry_coroutine_yield(r, L) #endif diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index ccf0288acd..7543a22df2 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -61,8 +61,9 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) { ngx_http_request_t *r; int n; - ngx_http_lua_ctx_t *ctx; ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); @@ -91,13 +92,18 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - return luaL_error(L, "request context is null"); + return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + coctx = ctx->cur_co_ctx; + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua start to read buffered request body"); @@ -113,6 +119,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) ctx->waiting_more_body = 1; ctx->req_read_body_done = 0; + ctx->req_body_reader_co_ctx = coctx; return lua_yield(L, 0); } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 434b0b52f0..3ecc0b6b3d 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -266,6 +266,8 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entry_co = co; ctx->cur_co = co; + ctx->cur_co_ctx = &ctx->entry_co_ctx; + ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; /* }}} */ diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 4163698535..f92129f97b 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -10,6 +10,7 @@ static int ngx_http_lua_ngx_sleep(lua_State *L); static void ngx_http_lua_sleep_handler(ngx_event_t *ev); +static void ngx_http_lua_co_cleanup(void *data); static int @@ -19,6 +20,8 @@ ngx_http_lua_ngx_sleep(lua_State *L) ngx_int_t delay; /* in msec */ ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_cleanup_t *cln; n = lua_gettop(L); if (n != 1) { @@ -47,14 +50,30 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "no request ctx found"); } - ctx->sleep.handler = ngx_http_lua_sleep_handler; - ctx->sleep.data = r; - ctx->sleep.log = r->connection->log; + coctx = ctx->cur_co_ctx; + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + + coctx->sleep.handler = ngx_http_lua_sleep_handler; + coctx->sleep.data = r; + coctx->sleep.log = r->connection->log; dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, (int) r->uri.len, r->uri.data); - ngx_add_timer(&ctx->sleep, (ngx_msec_t) delay); + ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); + + if (coctx->cleanup == NULL) { + cln = ngx_http_cleanup_add(r, 0); + if (cln == NULL) { + return luaL_error(L, "out of memory"); + } + + cln->handler = ngx_http_lua_co_cleanup; + cln->data = coctx; + coctx->cleanup = &cln->handler; + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); @@ -75,6 +94,7 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_log_ctx_t *log_ctx; + ngx_http_lua_co_ctx_t *coctx; r = ev->data; c = r->connection; @@ -91,7 +111,9 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep handler: \"%V?%V\"", &r->uri, &r->args); - if (!ctx->sleep.timedout) { + coctx = ctx->cur_co_ctx; + + if (!coctx->sleep.timedout) { dd("reach lua sleep event handler without timeout!"); return; } @@ -99,9 +121,9 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args); - if (ctx->sleep.timer_set) { + if (coctx->sleep.timer_set) { dd("deleting timer for lua_sleep"); - ngx_del_timer(&ctx->sleep); + ngx_del_timer(&coctx->sleep); } if (ctx->entered_content_phase) { @@ -122,3 +144,21 @@ ngx_http_lua_inject_sleep_api(lua_State *L) lua_setfield(L, -2, "sleep"); } + +static void +ngx_http_lua_co_cleanup(void *data) +{ + ngx_http_lua_co_ctx_t *coctx = data; + + if (coctx->cleanup) { + *coctx->cleanup = NULL; + coctx->cleanup = NULL; + } + + if (coctx->sleep.timer_set) { + dd("cleanup: deleting timer for 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 63ed85fe03..f117b8aaba 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -257,6 +257,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) unsigned custom_pool; int key_index; const char *msg; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; @@ -402,7 +403,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_http_lua_socket_tcp_upstream_t)); + coctx = ctx->cur_co_ctx; + u->request = r; /* set the controlling request */ + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); u->conf = llcf; @@ -556,9 +560,11 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - ctx->data = u; - ctx->socket_busy = 1; - ctx->socket_ready = 0; + dd("setting data to %p", u); + + coctx->data = u; + coctx->socket_busy = 1; + coctx->socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -581,6 +587,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) struct sockaddr_in *sin; ngx_uint_t i; unsigned waiting; + ngx_http_lua_co_ctx_t *coctx; u = ctx->data; r = u->request; @@ -590,6 +597,12 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) "lua tcp socket resolve handler"); lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + return; + } + + dd("ctx->cur_co_ctx = %p", lctx->cur_co_ctx); + dd("u->co_ctx = %p", u->co_ctx); L = lctx->cur_co; @@ -686,8 +699,10 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->waiting = 0; if (waiting) { - lctx->socket_busy = 0; - lctx->socket_ready = 1; + coctx = lctx->cur_co_ctx; + + coctx->socket_busy = 0; + coctx->socket_ready = 1; r->write_event_handler(r); } else { @@ -706,6 +721,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_cleanup_t *cln; ngx_http_upstream_resolved_t *ur; ngx_int_t rc; + ngx_http_lua_co_ctx_t *coctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket resolve retval handler"); @@ -802,7 +818,11 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - ctx->data = u; + coctx = ctx->cur_co_ctx; + + dd("setting data to %p", u); + + coctx->data = u; if (rc == NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -847,9 +867,11 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_connect_retval_handler; - ctx->data = u; - ctx->socket_busy = 1; - ctx->socket_ready = 0; + dd("setting data to %p", u); + + coctx->data = u; + coctx->socket_busy = 1; + coctx->socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -936,6 +958,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) char *p; int typ; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1 && n != 2) { @@ -1095,9 +1118,13 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - ctx->data = u; - ctx->socket_busy = 1; - ctx->socket_ready = 0; + coctx = ctx->cur_co_ctx; + + dd("setting data to %p, coctx:%p", u, coctx); + + coctx->data = u; + coctx->socket_busy = 1; + coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -1467,6 +1494,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L) const char *msg; ngx_buf_t *b; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_co_ctx_t *coctx; /* TODO: add support for the optional "i" and "j" arguments */ @@ -1610,9 +1638,13 @@ ngx_http_lua_socket_tcp_send(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler; - ctx->data = u; - ctx->socket_busy = 1; - ctx->socket_ready = 0; + dd("setting data to %p", u); + + coctx = ctx->cur_co_ctx; + + coctx->data = u; + coctx->socket_busy = 1; + coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -1967,6 +1999,7 @@ 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; @@ -1984,10 +2017,14 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + coctx = ctx->cur_co_ctx; + dd("setting socket_ready to 1"); + dd("prepare retvals: %p(%p), u:%p, ctx->data:%p", u->prepare_retvals, + ngx_http_lua_socket_tcp_receive_retval_handler, u, coctx->data); - ctx->socket_busy = 0; - ctx->socket_ready = 1; + coctx->socket_busy = 0; + coctx->socket_ready = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2002,6 +2039,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"); @@ -2020,10 +2058,12 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + coctx = ctx->cur_co_ctx; + dd("setting socket_ready to 1"); - ctx->socket_busy = 0; - ctx->socket_ready = 1; + coctx->socket_busy = 0; + coctx->socket_ready = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2337,6 +2377,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) ngx_http_lua_ctx_t *ctx; lua_Integer bytes; int n; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_compiled_pattern_t *cp; @@ -2455,9 +2496,13 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; - ctx->data = u; - ctx->socket_busy = 1; - ctx->socket_ready = 0; + coctx = ctx->cur_co_ctx; + + dd("setting data to %p", u); + + coctx->data = u; + coctx->socket_busy = 1; + coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -2781,6 +2826,7 @@ ngx_http_lua_req_socket(lua_State *L) ngx_http_lua_ctx_t *ctx; ngx_http_request_body_t *rb; ngx_http_cleanup_t *cln; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; @@ -2862,6 +2908,8 @@ ngx_http_lua_req_socket(lua_State *L) u->is_downstream = 1; + coctx = ctx->cur_co_ctx; + u->request = r; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -2892,7 +2940,9 @@ ngx_http_lua_req_socket(lua_State *L) c = r->connection; pc->connection = c; - ctx->data = u; + dd("setting data to %p", u); + + coctx->data = u; r->read_event_handler = ngx_http_lua_req_socket_rev_handler; @@ -2910,6 +2960,7 @@ static void ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) { ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *u; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -2920,7 +2971,9 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) return; } - u = ctx->data; + coctx = ctx->cur_co_ctx; + + u = coctx->data; if (u) { u->read_event_handler(r, u); diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index c4744e73bd..9d2d873df4 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -149,6 +149,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) ngx_http_lua_loc_conf_t *llcf; ngx_udp_connection_t *uc; int timeout; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_udp_upstream_t *u; @@ -371,9 +372,11 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - ctx->data = u; - ctx->udp_socket_busy = 1; - ctx->udp_socket_ready = 0; + coctx = ctx->cur_co_ctx; + + coctx->data = u; + coctx->udp_socket_busy = 1; + coctx->udp_socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -389,6 +392,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) ngx_http_request_t *r; ngx_http_upstream_resolved_t *ur; ngx_http_lua_ctx_t *lctx; + ngx_http_lua_co_ctx_t *coctx; lua_State *L; ngx_http_lua_socket_udp_upstream_t *u; u_char *p; @@ -503,8 +507,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->waiting = 0; if (waiting) { - lctx->udp_socket_busy = 0; - lctx->udp_socket_ready = 1; + coctx = lctx->cur_co_ctx; + + coctx->udp_socket_busy = 0; + coctx->udp_socket_ready = 1; + r->write_event_handler(r); } else { @@ -518,6 +525,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u, lua_State *L) { ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; ngx_udp_connection_t *uc; ngx_connection_t *c; ngx_http_cleanup_t *cln; @@ -590,7 +598,9 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - ctx->data = u; + coctx = ctx->cur_co_ctx; + + coctx->data = u; u->read_event_handler = ngx_http_lua_socket_dummy_handler; @@ -786,6 +796,7 @@ ngx_http_lua_socket_udp_receive(lua_State *L) ngx_http_lua_socket_udp_upstream_t *u; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; size_t size; int nargs; ngx_http_lua_loc_conf_t *llcf; @@ -880,9 +891,11 @@ ngx_http_lua_socket_udp_receive(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_udp_receive_retval_handler; - ctx->data = u; - ctx->udp_socket_busy = 1; - ctx->udp_socket_ready = 0; + coctx = ctx->cur_co_ctx; + + coctx->data = u; + coctx->udp_socket_busy = 1; + coctx->udp_socket_ready = 0; return lua_yield(L, 0); } @@ -1096,6 +1109,7 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_udp_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 udp socket handle error"); @@ -1115,8 +1129,10 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, dd("setting socket_ready to 1"); - ctx->udp_socket_busy = 0; - ctx->udp_socket_ready = 1; + coctx = ctx->cur_co_ctx; + + coctx->udp_socket_busy = 0; + coctx->udp_socket_ready = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); @@ -1174,6 +1190,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u) { ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; u->read_event_handler = ngx_http_lua_socket_dummy_handler; @@ -1184,8 +1201,10 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, dd("setting socket_ready to 1"); - ctx->udp_socket_busy = 0; - ctx->udp_socket_ready = 1; + coctx = ctx->cur_co_ctx; + + coctx->udp_socket_busy = 0; + coctx->udp_socket_ready = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 8221804be4..3522f55f9c 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -103,6 +103,9 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) size_t sr_headers_len; size_t sr_bodies_len; unsigned custom_ctx; + ngx_http_lua_co_ctx_t *coctx; + + ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { @@ -134,6 +137,11 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + coctx = ctx->cur_co_ctx; + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + 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); @@ -145,23 +153,23 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "out of memory"); } - ctx->sr_statuses = (void *) p; + coctx->sr_statuses = (void *) p; p += sr_statuses_len; - ctx->sr_headers = (void *) p; + coctx->sr_headers = (void *) p; p += sr_headers_len; - ctx->sr_bodies = (void *) p; + coctx->sr_bodies = (void *) p; - ctx->nsubreqs = nsubreqs; + coctx->nsubreqs = nsubreqs; - ctx->done = 0; - ctx->waiting = 0; + coctx->done = 0; + coctx->waiting = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { - ctx->waiting++; + coctx->waiting++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { @@ -459,17 +467,26 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) args.len = len; } - psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); - if (psr == NULL) { - return luaL_error(L, "memory allocation error"); - } - - sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); - if (sr_ctx == NULL) { + p = ngx_pnalloc(r->pool, sizeof(ngx_http_post_subrequest_t) + + sizeof(ngx_http_lua_ctx_t) + + sizeof(ngx_http_lua_post_subrequest_data_t)); + if (p == NULL) { return luaL_error(L, "out of memory"); } - /* set by ngx_pcalloc: + psr = (ngx_http_post_subrequest_t *) p; + + p += sizeof(ngx_http_post_subrequest_t); + + sr_ctx = (ngx_http_lua_ctx_t *) p; + + p += sizeof(ngx_http_lua_ctx_t); + + psr_data = (ngx_http_lua_post_subrequest_data_t *) p; + + ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); + + /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL */ @@ -481,8 +498,11 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) sr_ctx->index = index; + psr_data->ctx = sr_ctx; + psr_data->pr_co_ctx = coctx; + psr->handler = ngx_http_lua_post_subrequest; - psr->data = sr_ctx; + psr->data = psr_data; rc = ngx_http_subrequest(r, &uri, &args, &sr, psr, 0); @@ -797,19 +817,23 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) { ngx_http_request_t *pr; ngx_http_lua_ctx_t *pr_ctx; - ngx_http_lua_ctx_t *ctx = data; + ngx_http_lua_ctx_t *ctx; /* subrequest ctx */ + ngx_http_lua_co_ctx_t *pr_coctx; size_t len; ngx_str_t *body_str; u_char *p; ngx_chain_t *cl; + ngx_http_lua_post_subrequest_data_t *psr_data = data; + + ctx = psr_data->ctx; + if (ctx->run_post_subrequest) { return rc; } - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run post subrequest handler: rc:%d, waiting:%d, done:%d", - rc, ctx->waiting, ctx->done); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run post subrequest handler: rc:%d", rc); ctx->run_post_subrequest = 1; @@ -820,10 +844,12 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) return NGX_ERROR; } - pr_ctx->waiting--; + pr_coctx = psr_data->pr_co_ctx; - if (pr_ctx->waiting == 0) { - pr_ctx->done = 1; + pr_coctx->waiting--; + + if (pr_coctx->waiting == 0) { + pr_coctx->done = 1; } if (pr_ctx->entered_content_phase) { @@ -839,30 +865,28 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) /* capture subrequest response status */ if (rc == NGX_ERROR) { - pr_ctx->sr_statuses[ctx->index] = NGX_HTTP_INTERNAL_SERVER_ERROR; + pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_INTERNAL_SERVER_ERROR; } else if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - dd("HERE"); - pr_ctx->sr_statuses[ctx->index] = rc; + pr_coctx->sr_statuses[ctx->index] = rc; } else { - dd("THERE"); - pr_ctx->sr_statuses[ctx->index] = r->headers_out.status; + pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; } - if (pr_ctx->sr_statuses[ctx->index] == 0) { - pr_ctx->sr_statuses[ctx->index] = NGX_HTTP_OK; + if (pr_coctx->sr_statuses[ctx->index] == 0) { + pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_OK; } - dd("pr_ctx status: %d", (int) pr_ctx->sr_statuses[ctx->index]); + dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ - pr_ctx->sr_headers[ctx->index] = &r->headers_out; + pr_coctx->sr_headers[ctx->index] = &r->headers_out; /* copy subrequest response body */ - body_str = &pr_ctx->sr_bodies[ctx->index]; + body_str = &pr_coctx->sr_bodies[ctx->index]; len = 0; for (cl = ctx->body; cl; cl = cl->next) { @@ -886,8 +910,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) /* copy from and then free the data buffers */ for (cl = ctx->body; cl; cl = cl->next) { - p = ngx_copy(p, cl->buf->pos, - cl->buf->last - cl->buf->pos); + p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos); cl->buf->last = cl->buf->pos; @@ -914,9 +937,10 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) /* work-around issues in nginx's event module */ - if (r != r->connection->data && r->postponed && - (r->main->posted_requests == NULL || - r->main->posted_requests->request != pr)) + if (r != r->connection->data + && r->postponed + && (r->main->posted_requests == NULL + || r->main->posted_requests->request != pr)) { #if defined(nginx_version) && nginx_version >= 8012 ngx_http_post_request(pr, NULL); @@ -1033,38 +1057,40 @@ 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 index; lua_State *co; ngx_str_t *body_str; ngx_table_elt_t *header; ngx_list_part_t *part; ngx_http_headers_out_t *sr_headers; - ngx_uint_t i; + ngx_http_lua_co_ctx_t *coctx; u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua handle subrequest responses"); + "lua handle subrequest responses"); - for (index = 0; index < ctx->nsubreqs; index++) { + co = ctx->cur_co; + coctx = ctx->cur_co_ctx; + + for (index = 0; index < coctx->nsubreqs; index++) { dd("summary: reqs %d, subquery %d, waiting %d, req %.*s", - (int) ctx->nsubreqs, + (int) coctx->nsubreqs, (int) index, - (int) ctx->waiting, + (int) coctx->waiting, (int) r->uri.len, r->uri.data); - co = ctx->cur_co; - /* {{{ construct ret value */ lua_newtable(co); /* copy captured status */ - lua_pushinteger(co, ctx->sr_statuses[index]); + lua_pushinteger(co, coctx->sr_statuses[index]); lua_setfield(co, -2, "status"); /* copy captured body */ - body_str = &ctx->sr_bodies[index]; + body_str = &coctx->sr_bodies[index]; lua_pushlstring(co, (char *) body_str->data, body_str->len); lua_setfield(co, -2, "body"); @@ -1078,7 +1104,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, lua_newtable(co); /* res.header */ - sr_headers = ctx->sr_headers[index]; + sr_headers = coctx->sr_headers[index]; dd("saving subrequest response headers"); diff --git a/src/ngx_http_lua_subrequest.h b/src/ngx_http_lua_subrequest.h index 2cd342dedf..64f5512580 100644 --- a/src/ngx_http_lua_subrequest.h +++ b/src/ngx_http_lua_subrequest.h @@ -20,5 +20,12 @@ extern ngx_str_t ngx_http_lua_delete_method; extern ngx_str_t ngx_http_lua_options_method; +typedef struct ngx_http_lua_post_subrequest_data_s { + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *pr_co_ctx; + +} ngx_http_lua_post_subrequest_data_t; + + #endif /* NGX_HTTP_LUA_SUBREQUEST_H */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 163cbda681..b267e634d4 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -37,6 +37,7 @@ #include "ngx_http_lua_bodyfilterby.h" #include "ngx_http_lua_logby.h" #include "ngx_http_lua_phase.h" +#include "ngx_http_lua_probe.h" char ngx_http_lua_code_cache_key; @@ -44,7 +45,6 @@ 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_coroutine_parents_key; /* coroutine anchoring table key in Lua vm registry */ @@ -62,7 +62,8 @@ static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int entry_ref); static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int entry_ref); -static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co); +static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, + ngx_http_lua_co_ctx_t *coctx); static void ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L); static void ngx_http_lua_inject_arg_api(lua_State *L); static int ngx_http_lua_param_get(lua_State *L); @@ -541,23 +542,6 @@ ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L) lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ - /* {{{ create weak table to record coroutine parent relationship: - * { [(thread)child] = (thread)parent } */ - - lua_pushlightuserdata(L, &ngx_http_lua_coroutine_parents_key); - lua_newtable(L); - - /* create metatable */ - lua_createtable(L, 0, 1 /* nrec */); - lua_pushstring(L, "kv"); - lua_setfield(L, -2, "__mode"); - - /* setup metatable to make key/val weak-ref table */ - lua_setmetatable(L, -2); - - lua_rawset(L, LUA_REGISTRYINDEX); - /* }}} */ - lua_pushlightuserdata(L, &ngx_http_lua_cf_log_key); lua_pushlightuserdata(L, cf->log); lua_rawset(L, LUA_REGISTRYINDEX); @@ -704,8 +688,12 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->entry_ref = LUA_NOREF; } - ctx->waiting = 0; - ctx->done = 0; + if (ctx->user_co_ctx) { + ngx_array_destroy(ctx->user_co_ctx); + ctx->user_co_ctx = NULL; + } + + ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t)); ctx->entered_rewrite_phase = 0; ctx->entered_access_phase = 0; @@ -713,12 +701,13 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->exit_code = 0; ctx->exited = 0; - ctx->exec_uri.data = NULL; - ctx->exec_uri.len = 0; - ctx->sr_statuses = NULL; - ctx->sr_headers = NULL; - ctx->sr_bodies = NULL; + ngx_str_null(&ctx->exec_uri); + ngx_str_null(&ctx->exec_args); + + ctx->co_op = 0; + + ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t)); } @@ -756,7 +745,7 @@ ngx_http_lua_request_cleanup(void *data) ngx_http_lua_main_conf_t *lmcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua request cleanup"); + "lua request cleanup"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -770,12 +759,6 @@ ngx_http_lua_request_cleanup(void *data) ctx->cleanup = NULL; } - if (ctx->sleep.timer_set) { - dd("cleanup: deleting timer for ngx.sleep"); - - ngx_del_timer(&ctx->sleep); - } - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); L = lmcf->lua; @@ -828,8 +811,10 @@ 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; int rv, nrets; - lua_State *co, *next_co; + lua_State *next_co; + lua_State *old_co; const char *err, *msg, *trace; ngx_int_t rc; #if (NGX_PCRE) @@ -847,12 +832,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, NGX_LUA_EXCEPTION_TRY { - co = ctx->cur_co; nrets = nret; for ( ;; ) { - dd("calling lua_resume: vm %p, nret %d", co, (int) nret); + dd("calling lua_resume: vm %p, nret %d", ctx->cur_co, (int) nret); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -861,7 +845,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, #endif /* run code */ - rv = lua_resume(co, nrets); + dd("ctx: %p", ctx); + dd("cur co: %p", ctx->cur_co); + + rv = lua_resume(ctx->cur_co, nrets); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -908,7 +895,7 @@ 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(co, 0); + lua_settop(ctx->cur_co, 0); return NGX_AGAIN; case NGX_HTTP_LUA_USER_CORO_RESUME: @@ -921,51 +908,40 @@ 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(co) - 1; - next_co = lua_tothread(co, 1); + old_co = ctx->cur_co_ctx->parent_co_ctx->co; - /* move any args to the target coroutine */ + nrets = lua_gettop(old_co); if (nrets) { - lua_xmove(co, next_co, nrets); + lua_xmove(old_co, ctx->cur_co, nrets); } - co = next_co; - ctx->cur_co = co; - break; default: - /* NGX_HTTP_LUA_USER_CORO_YIELD */ + /* ctx->co_op == NGX_HTTP_LUA_USER_CORO_YIELD */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua coroutine: yield"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - - if (co == ctx->entry_co) { + if (ctx->cur_co == ctx->entry_co) { /* entry coroutine yielded will be resumed * immediately */ - lua_settop(co, 0); /* discard the return values */ + + ngx_http_lua_probe_entry_coroutine_yield(r, + ctx->cur_co); + + lua_settop(ctx->cur_co, 0); nrets = 0; continue; } /* being a user coroutine that has a parent */ - nrets = lua_gettop(co); + nrets = lua_gettop(ctx->cur_co); - /* find parent coroutine in weak ref table */ - ngx_http_lua_get_coroutine_parents(L); - lua_pushthread(co); - lua_xmove(co, L, 1); - lua_rawget(L, -2); - - next_co = lua_tothread(L, -1); - if (next_co == NULL) { - goto no_parent; - } - - lua_pop(L, 2); + next_coctx = ctx->cur_co_ctx->parent_co_ctx; + next_co = next_coctx->co; /* * prepare return values for coroutine.resume @@ -974,12 +950,13 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_pushboolean(next_co, 1); if (nrets) { - lua_xmove(co, next_co, nrets); + lua_xmove(ctx->cur_co, next_co, nrets); } nrets++; - co = next_co; - ctx->cur_co = co; + + ctx->cur_co_ctx = next_coctx; + ctx->cur_co = next_co; break; } @@ -989,7 +966,9 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, case 0: - if (co == ctx->entry_co) { + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + + if (ctx->cur_co == ctx->entry_co) { dd("hit! it is the entry"); lua_settop(L, 0); /* discard return values */ @@ -1017,19 +996,16 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* being a user coroutine that has a parent */ - nrets = lua_gettop(co); + nrets = lua_gettop(ctx->cur_co); - ngx_http_lua_get_coroutine_parents(L); - lua_pushthread(co); - lua_xmove(co, L, 1); - lua_rawget(L, -2); + next_coctx = ctx->cur_co_ctx->parent_co_ctx; - next_co = lua_tothread(L, -1); - if (next_co == NULL) { + if (next_coctx == NULL) { + /* being a lightweight thread */ goto no_parent; } - lua_pop(L, 2); + next_co = next_coctx->co; /* * ended successful, coroutine.resume returns true plus @@ -1038,12 +1014,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_pushboolean(next_co, 1); if (nrets) { - lua_xmove(co, next_co, nrets); + lua_xmove(ctx->cur_co, next_co, nrets); } nrets++; - co = next_co; - ctx->cur_co = co; + ctx->cur_co = next_co; + ctx->cur_co_ctx = next_coctx; + + dd("set coroutine to running"); + next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua coroutine: lua user thread ended normally"); @@ -1051,39 +1030,44 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, continue; case LUA_ERRRUN: + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "runtime error"; break; case LUA_ERRSYNTAX: + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "syntax error"; break; case LUA_ERRMEM: + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "memory allocation error"; break; case LUA_ERRERR: + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "error handler error"; break; default: + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "unknown error"; break; } - if (lua_isstring(co, -1)) { + if (lua_isstring(ctx->cur_co, -1)) { dd("user custom error msg"); - msg = lua_tostring(co, -1); + msg = lua_tostring(ctx->cur_co, -1); } else { msg = "unknown reason"; } - ngx_http_lua_thread_traceback(L, co); + ngx_http_lua_thread_traceback(L, ctx->cur_co, ctx->cur_co_ctx); trace = lua_tostring(L, -1); lua_pop(L, 1); - if (co == ctx->entry_co) { + if (ctx->cur_co == ctx->entry_co) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: %s: %s\n%s", err, msg, trace); @@ -1103,28 +1087,23 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* being a user coroutine that has a parent */ - ngx_http_lua_get_coroutine_parents(L); - lua_pushthread(co); - lua_xmove(co, L, 1); - lua_rawget(L, -2); - - next_co = lua_tothread(L, -1); - if (next_co == NULL) { + next_coctx = ctx->cur_co_ctx->parent_co_ctx; + if (next_coctx == NULL) { goto no_parent; } - lua_pop(L, 2); + next_co = next_coctx->co; /* * ended with error, coroutine.resume returns false plus * err msg */ lua_pushboolean(next_co, 0); - lua_xmove(co, next_co, 1); + lua_xmove(ctx->cur_co, next_co, 1); nrets = 2; - co = next_co; - ctx->cur_co = co; + ctx->cur_co = next_co; + ctx->cur_co_ctx = next_coctx; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua coroutine: %s: %s\n%s", err, msg, trace); @@ -1158,8 +1137,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 ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -1174,6 +1152,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; ngx_chain_t *cl; + ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_tcp_upstream_t *tcp; ngx_http_lua_socket_udp_upstream_t *udp; @@ -1190,6 +1169,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto error; } + coctx = ctx->cur_co_ctx; + clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); if (wev->timedout) { @@ -1243,17 +1224,17 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (ctx->waiting_more_body && !ctx->req_read_body_done) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua write event handler waiting for more request body data"); + "lua write event handler waiting for more request " + "body data"); return NGX_DONE; } - dd("waiting: %d, done: %d", (int) ctx->waiting, - ctx->done); + dd("waiting: %d, done: %d", (int) coctx->waiting, coctx->done); - if (ctx->waiting && !ctx->done) { + if (coctx->waiting && !coctx->done) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua waiting for pending subrequests"); + "lua waiting for pending subrequests"); if (r == c->data && r->postponed) { if (r->postponed->request) { @@ -1331,7 +1312,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_ERROR; } - if (ctx->waiting_flush) { + if (coctx->waiting_flush) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua flush still waiting: buffered 0x%uxd", c->buffered); @@ -1341,7 +1322,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (ctx->sleep.timer_set) { + if (coctx->sleep.timer_set) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua still waiting for a sleep timer: \"%V?%V\"", &r->uri, &r->args); @@ -1353,24 +1334,24 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } - if (ctx->sleep.timedout) { - ctx->sleep.timedout = 0; + if (coctx->sleep.timedout) { + coctx->sleep.timedout = 0; nret = 0; goto run; } - if (ctx->socket_busy && !ctx->socket_ready) { + if (coctx->socket_busy && !coctx->socket_ready) { return NGX_DONE; } - if (ctx->udp_socket_busy && !ctx->udp_socket_ready) { + if (coctx->udp_socket_busy && !coctx->udp_socket_ready) { return NGX_DONE; } - if (!ctx->udp_socket_busy && ctx->udp_socket_ready) { - ctx->udp_socket_ready = 0; + if (!coctx->udp_socket_busy && coctx->udp_socket_ready) { + coctx->udp_socket_ready = 0; - udp = ctx->data; + udp = coctx->data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua dup socket calling prepare retvals handler %p", @@ -1384,19 +1365,19 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto run; } - if (!ctx->socket_busy && ctx->socket_ready) { + if (!coctx->socket_busy && coctx->socket_ready) { dd("resuming socket api"); dd("setting socket_ready to 0"); - ctx->socket_ready = 0; + coctx->socket_ready = 0; - tcp = ctx->data; + tcp = coctx->data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket calling prepare retvals handler %p", - tcp->prepare_retvals); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket calling prepare retvals handler %p, " + "u:%p", tcp->prepare_retvals, tcp); nret = tcp->prepare_retvals(r, tcp, ctx->cur_co); if (nret == NGX_AGAIN) { @@ -1405,9 +1386,9 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto run; - } else if (ctx->waiting_flush) { + } else if (coctx->waiting_flush) { - ctx->waiting_flush = 0; + coctx->waiting_flush = 0; nret = 0; goto run; @@ -1425,28 +1406,28 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto run; - } else if (ctx->done) { + } else if (coctx->done) { - ctx->done = 0; + coctx->done = 0; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua run subrequests done, resuming lua thread"); - dd("nsubreqs: %d", (int) ctx->nsubreqs); + dd("nsubreqs: %d", (int) coctx->nsubreqs); ngx_http_lua_handle_subreq_responses(r, ctx); dd("free sr_statues/headers/bodies memory ASAP"); #if 1 - ngx_pfree(r->pool, ctx->sr_statuses); + ngx_pfree(r->pool, coctx->sr_statuses); - ctx->sr_statuses = NULL; - ctx->sr_headers = NULL; - ctx->sr_bodies = NULL; + coctx->sr_statuses = NULL; + coctx->sr_headers = NULL; + coctx->sr_bodies = NULL; #endif - nret = ctx->nsubreqs; + nret = coctx->nsubreqs; dd("location capture nret: %d", (int) nret); @@ -1942,8 +1923,6 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, return rc; } - dd("XXYY HERE %d\n", (int) r->main->count); - #if 0 if (!ctx->entered_content_phase) { /* XXX ensure the main request ref count @@ -2433,15 +2412,14 @@ ngx_http_lua_chains_get_free_buf(ngx_log_t *log, ngx_pool_t *p, static int -ngx_http_lua_thread_traceback(lua_State *L, lua_State *co) +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 `...' */ lua_Debug ar; - ngx_http_lua_get_coroutine_parents(L); - base = lua_gettop(L); lua_pushliteral(L, "stack traceback:"); @@ -2502,16 +2480,14 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co) firstpart = 1; /* check if the coroutine has a parent coroutine*/ - lua_pushthread(co); - lua_xmove(co, L, 1); - lua_rawget(L, -3); + coctx = coctx->parent_co_ctx; + if (!coctx) { + break; + } - co = lua_tothread(L, -1); - lua_pop(L, 1); + co = coctx->co; } - lua_remove(L, -2); - return 1; } @@ -2622,3 +2598,54 @@ ngx_http_lua_param_set(lua_State *L) return ngx_http_lua_body_filter_param_set(L, r, ctx); } + +ngx_http_lua_co_ctx_t * +ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx) +{ + ngx_uint_t i; + ngx_http_lua_co_ctx_t *coctx; + + if (L == ctx->entry_co) { + return &ctx->entry_co_ctx; + } + + if (ctx->user_co_ctx == NULL) { + return NULL; + } + + coctx = ctx->user_co_ctx->elts; + + /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ + + for (i = 0; i < ctx->user_co_ctx->nelts; i++) { + if (L == coctx[i].co) { + return &coctx[i]; + } + } + + return NULL; +} + + +ngx_http_lua_co_ctx_t * +ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_http_lua_co_ctx_t *coctx; + + if (ctx->user_co_ctx == NULL) { + ctx->user_co_ctx = ngx_array_create(r->pool, 4, + sizeof(ngx_http_lua_co_ctx_t)); + if (ctx->user_co_ctx == NULL) { + return NULL; + } + } + + coctx = ngx_array_push(ctx->user_co_ctx); + if (coctx == NULL) { + return NULL; + } + + ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t)); + return coctx; +} + diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 8db9f476c5..6f9fbfe73c 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -120,6 +120,12 @@ void ngx_http_lua_create_new_global_table(lua_State *L, int narr, int nrec); int ngx_http_lua_traceback(lua_State *L); +ngx_http_lua_co_ctx_t * ngx_http_lua_get_co_ctx(lua_State *L, + ngx_http_lua_ctx_t *ctx); + +ngx_http_lua_co_ctx_t * ngx_http_lua_create_co_ctx(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx); + #endif /* NGX_HTTP_LUA_UTIL_H */ diff --git a/t/014-bugs.t b/t/014-bugs.t index 06d4f44482..0ca63a857f 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -19,6 +19,9 @@ our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +#no_shuffle(); +no_long_string(); + run_tests(); __DATA__ diff --git a/t/017-exec.t b/t/017-exec.t index e7fac0497e..b043360b96 100644 --- a/t/017-exec.t +++ b/t/017-exec.t @@ -7,11 +7,12 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 2 + 4); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + #no_diff(); +#no_shuffle(); #no_long_string(); -$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; - run_tests(); __DATA__ @@ -539,6 +540,7 @@ hello proxy_pass http://127.0.0.1:$server_port/foo; } location /foo { + #echo_status 201; echo bah; } --- request diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 290c358f87..95e72c33d1 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -16,6 +16,8 @@ $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; #no_diff(); #no_long_string(); +#no_shuffle(); + run_tests(); __DATA__ @@ -808,7 +810,7 @@ bar --- http_config upstream memc { server 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; - keepalive 100 single; + keepalive 100; } --- config location /memc { diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t index 57aa4877f0..9e41264fb7 100644 --- a/t/061-lua-redis.t +++ b/t/061-lua-redis.t @@ -22,6 +22,7 @@ our $LuaCpath = $ENV{LUA_CPATH} || '/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;'; no_long_string(); + run_tests(); __DATA__ @@ -72,12 +73,15 @@ qq{ local loop = r2:pubsub({ subscribe = "foo" }) local msg, abort = loop() ngx.say("msg type: ", type(msg)) + ngx.say("abort: ", type(abort)) + if msg then ngx.say("msg: ", cjson.encode(msg)) end + for i = 1, 3 do r1:publish("foo", "test " .. i) - local msg, abort = loop() + msg, abort = loop() if msg then ngx.say("msg: ", cjson.encode(msg)) end @@ -90,10 +94,86 @@ qq{ ngx.say("msg type: ", type(msg)) '; } +--- stap2 +global ids, cur + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_handler) { + delete ids + cur = 0 +} + +/* +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_yield") { + id = gen_id($L) + printf("raw lua yield %d\n", id) + #print_ubacktrace() +} + +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { + id = gen_id($L) + printf("raw lua resume %d\n", id) +} +*/ + +/* +F(ngx_http_lua_run_thread) { + id = gen_id($ctx->cur_co) + printf("run thread %d\n", id) +} +*/ + +M(http-lua-user-coroutine-resume) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("resume %x in %x\n", c, p) +} + +M(http-lua-entry-coroutine-yield) { + println("entry coroutine yield") +} + +F(ngx_http_lua_coroutine_yield) { + printf("yield %x\n", gen_id($L)) +} + +/* +F(ngx_http_lua_coroutine_resume) { + printf("resume %x\n", gen_id($L)) +} +*/ + +M(http-lua-user-coroutine-yield) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("yield %x in %x\n", c, p) +} + +F(ngx_http_lua_atpanic) { + printf("lua atpanic(%d):", gen_id($L)) + print_ubacktrace(); +} + +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + +F(ngx_http_lua_ngx_exec) { println("exec") } + +F(ngx_http_lua_ngx_exit) { println("exit") } + --- request GET /test --- response_body msg type: table +abort: function msg: {"payload":1,"channel":"foo","kind":"subscribe"} msg: {"payload":"test 1","channel":"foo","kind":"message"} abort: function diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 7981af662e..0b4f49978d 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -23,15 +23,44 @@ F(ngx_http_handler) { cur = 0 } +/* +F(ngx_http_lua_run_thread) { + id = gen_id($ctx->cur_co) + printf("run thread %d\n", id) +} + +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { + id = gen_id($L) + printf("lua resume %d\n", id) +} +*/ + M(http-lua-user-coroutine-resume) { p = gen_id($arg2) c = gen_id($arg3) printf("resume %x in %x\n", c, p) } +M(http-lua-entry-coroutine-yield) { + println("entry coroutine yield") +} + +/* F(ngx_http_lua_coroutine_yield) { printf("yield %x\n", gen_id($L)) } +*/ + +M(http-lua-user-coroutine-yield) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("yield %x in %x\n", c, p) +} + +F(ngx_http_lua_atpanic) { + printf("lua atpanic(%d):", gen_id($L)) + print_ubacktrace(); +} M(http-lua-user-coroutine-create) { p = gen_id($arg2) @@ -44,6 +73,7 @@ F(ngx_http_lua_ngx_exec) { println("exec") } F(ngx_http_lua_ngx_exit) { println("exit") } _EOC_ +no_shuffle(); no_long_string(); run_tests(); @@ -57,7 +87,7 @@ __DATA__ function f() local cnt = 0 - while true do + for i = 1, 20 do ngx.say("Hello, ", cnt) cy() cnt = cnt + 1 @@ -73,6 +103,7 @@ __DATA__ } --- request GET /lua +--- stap2 eval: $::StapScript --- response_body Hello, 0 *** @@ -384,30 +415,30 @@ successfully connected to: openresty.org function f(self) local cnt = 0 if rn() ~= self then ngx.say("error"); return end - ngx.say(st(self)) --running + ngx.say("running: ", st(self)) --running cy() - -- Status normal is not support now. Actually user coroutines have no - -- sub-coroutine, the main thread holds all of the coroutines. - local c = cc(function(father) ngx.say(st(father)) end) -- normal + local c = cc(function(father) + ngx.say("normal: ", st(father)) + end) -- normal cr(c, self) end local c = cc(f) - ngx.say(st(c)) --suspended + ngx.say("suspended: ", st(c)) -- suspended cr(c, c) - ngx.say(st(c)) --suspended + ngx.say("suspended: ", st(c)) -- suspended cr(c, c) - ngx.say(st(c)) --dead + ngx.say("dead: ", st(c)) -- dead '; } --- request GET /lua --- response_body -suspended -running -suspended -suspended -dead +suspended: suspended +running: running +suspended: suspended +normal: normal +dead: dead --- no_error_log [error] @@ -625,11 +656,11 @@ GET /lua create 2 in 1 resume 2 in 1 create 3 in 2 -yield 2 +yield 2 in 1 resume 2 in 1 resume 3 in 2 -yield 3 -yield 2 +yield 3 in 2 +yield 2 in 1 resume 2 in 1 resume 3 in 2 exit @@ -684,11 +715,11 @@ exit create 2 in 1 resume 2 in 1 create 3 in 2 -yield 2 +yield 2 in 1 resume 2 in 1 resume 3 in 2 -yield 3 -yield 2 +yield 3 in 2 +yield 2 in 1 resume 2 in 1 resume 3 in 2 exec @@ -766,7 +797,7 @@ f 2 --- config location /t { content_by_lua ' - -- local print = ngx.say + local print = ngx.say local c1, c2 @@ -790,15 +821,16 @@ f 2 } --- request GET /t +--- stap2 eval: $::StapScript --- response_body f 1 g 1 +falsecannot resume normal coroutine g 2 true f 2 --- no_error_log [error] ---- SKIP diff --git a/valgrind.suppress b/valgrind.suppress index 4ae54439a6..21e39ad99c 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -589,4 +589,13 @@ fun:ngx_http_lua_ngx_echo fun:ngx_palloc_block fun:ngx_palloc } - +{ + + Memcheck:Param + sendmsg(msg.msg_iov[0]) + fun:__sendmsg_nocancel + fun:ngx_write_channel + fun:ngx_signal_worker_processes + fun:ngx_master_process_cycle + fun:main +} From 35c1fcd04e157fe1f084e8bfa7fa75a27a152028 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 28 Aug 2012 16:23:33 -0700 Subject: [PATCH 0003/2239] docs: removed the note for the issues regarding "normal" state user coroutines in coroutine.resume() and coroutine.status() because we have already fixed them. --- README | 8 -------- README.markdown | 4 ---- doc/HttpLuaModule.wiki | 4 ---- 3 files changed, 16 deletions(-) diff --git a/README b/README index b04ebfe6e5..24350f45a7 100644 --- a/README +++ b/README @@ -4561,10 +4561,6 @@ Nginx API for Lua but works in the context of the Lua coroutines created automatically by this Nginx module. - Due to the limitation in the current implementation, there is no - protection against resuming a user coroutine in the "normal" state. This - issue will be addressed in the near future. - This API was first introduced in the "v0.6.0" release. coroutine.yield @@ -4611,10 +4607,6 @@ Nginx API for Lua Identical to the standard Lua coroutine.status () API. - Note that due to the current implementation, this function will - incorrectly return "suspended" for "normal" coroutines. This issue will - be addressed in the near future. - This API was first enabled in the "v0.6.0" release. ndk.set_var.DIRECTIVE diff --git a/README.markdown b/README.markdown index 5fcbb753fa..955668e6be 100644 --- a/README.markdown +++ b/README.markdown @@ -4105,8 +4105,6 @@ Resumes the executation of a user Lua coroutine object previously yielded or jus Just behaves like 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 automatically by this Nginx module. -Due to the limitation in the current implementation, there is no protection against resuming a user coroutine in the `normal` state. This issue will be addressed in the near future. - This API was first introduced in the `v0.6.0` release. coroutine.yield @@ -4149,8 +4147,6 @@ coroutine.status Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status) API. -Note that due to the current implementation, this function will incorrectly return `"suspended"` for `"normal"` coroutines. This issue will be addressed in the near future. - This API was first enabled in the `v0.6.0` release. ndk.set_var.DIRECTIVE diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index bc1ed139e0..2486e8b6ba 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3962,8 +3962,6 @@ Resumes the executation of a user Lua coroutine object previously yielded or jus Just behaves like 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 automatically by this Nginx module. -Due to the limitation in the current implementation, there is no protection against resuming a user coroutine in the normal state. This issue will be addressed in the near future. - This API was first introduced in the v0.6.0 release. == coroutine.yield == @@ -4002,8 +4000,6 @@ This API was first enabled in the v0.6.0 release. Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-coroutine.status coroutine.status] API. -Note that due to the current implementation, this function will incorrectly return "suspended" for "normal" coroutines. This issue will be addressed in the near future. - This API was first enabled in the v0.6.0 release. == ndk.set_var.DIRECTIVE == From 62d67ad2f2682e2a5c86b75cf3a04fe1f53d2e05 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 29 Aug 2012 11:59:39 -0700 Subject: [PATCH 0004/2239] optimize: removed a duplidate ngx_memzero invocation in ngx_http_lua_reset_ctx. thanks jinglong. --- src/ngx_http_lua_util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 148b6cab4f..c4ab35636a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -706,8 +706,6 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_str_null(&ctx->exec_args); ctx->co_op = 0; - - ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t)); } From ce1bcd53cbbc71bf46c007315bdd656d2c2190a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 29 Aug 2012 12:17:38 -0700 Subject: [PATCH 0005/2239] bugfix: when a user coroutine died with an error, its parent coroutine's status was still 'normal'. thanks jinglong for reporting this issue. --- src/ngx_http_lua_util.c | 2 ++ t/091-coroutine.t | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index c4ab35636a..ede8b13017 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1092,6 +1092,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, next_co = next_coctx->co; + next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + /* * ended with error, coroutine.resume returns false plus * err msg diff --git a/t/091-coroutine.t b/t/091-coroutine.t index c04ca6f33e..bd83d0b4b6 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -877,3 +877,28 @@ chunk: true --- no_error_log [error] + + +=== TEST 21: user coroutine end with errors, and the parent coroutine gets the right status +--- config + location /t { + content_by_lua ' + local co + function f() + error("bad") + end + co = coroutine.create(f) + ngx.say("child: resume: ", coroutine.resume(co)) + ngx.say("child: status: ", coroutine.status(co)) + ngx.say("parent: status: ", coroutine.status(coroutine.running())) + '; + } +--- request +GET /t +--- response_body +child: resume: false[string "content_by_lua"]:4: bad +child: status: dead +parent: status: running +--- error_log +lua coroutine: runtime error: [string "content_by_lua"]:4: bad + From 7819b4284a39ec61ea7b64574b39becb42e38dcd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 29 Aug 2012 12:29:15 -0700 Subject: [PATCH 0006/2239] fixed typos in the test titles. --- t/023-rewrite/sleep.t | 2 +- t/024-access/sleep.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index 1ca29b930c..2f8255e1d3 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -62,7 +62,7 @@ bad argument #1 to 'sleep' -=== TEST 3: sleep 0.5 in subrequestg +=== TEST 3: sleep 0.5 in subrequest --- config location /test { rewrite_by_lua ' diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t index d4c162d0a3..fff250d42b 100644 --- a/t/024-access/sleep.t +++ b/t/024-access/sleep.t @@ -62,7 +62,7 @@ bad argument #1 to 'sleep' -=== TEST 3: sleep 0.5 in subrequestg +=== TEST 3: sleep 0.5 in subrequest --- config location /test { access_by_lua ' From fd0a8fb182f045f9e71018dd8031730fa70f3d5f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 29 Aug 2012 18:08:24 -0700 Subject: [PATCH 0007/2239] refactor: now ngx_lua issues subrequests without updating r->postponed at all so as to allow the parent requests flush outputs immediately without waiting for its running subrequests. this will pave a way for subrequest integration with the upcoming lightweight thread model. --- src/ngx_http_lua_subrequest.c | 164 +++++++++++++++++++++++++++++++--- src/ngx_http_lua_util.c | 25 +----- 2 files changed, 155 insertions(+), 34 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 3522f55f9c..18983e6fae 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -7,6 +7,9 @@ #include "ngx_http_lua_util.h" #include "ngx_http_lua_ctx.h" #include "ngx_http_lua_contentby.h" +#if defined(NGX_DTRACE) && NGX_DTRACE +#include "ngx_http_probe.h" +#endif #define NGX_HTTP_LUA_SHARE_ALL_VARS 0x01 @@ -40,6 +43,9 @@ static void ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L, int table, ngx_array_t **varsp); static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r, ngx_array_t *extra_vars); +static ngx_int_t ngx_http_lua_subrequest(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags); /* ngx.location.capture is just a thin wrapper around @@ -504,7 +510,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) psr->handler = ngx_http_lua_post_subrequest; psr->data = psr_data; - rc = ngx_http_subrequest(r, &uri, &args, &sr, psr, 0); + rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); @@ -937,16 +943,8 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) /* work-around issues in nginx's event module */ - if (r != r->connection->data - && r->postponed - && (r->main->posted_requests == NULL - || r->main->posted_requests->request != pr)) - { -#if defined(nginx_version) && nginx_version >= 8012 - ngx_http_post_request(pr, NULL); -#else - ngx_http_post_request(pr); -#endif + if (r != r->connection->data) { + r->connection->data = r; } return rc; @@ -1252,3 +1250,147 @@ ngx_http_lua_inject_subrequest_api(lua_State *L) lua_setfield(L, -2, "location"); } + +static ngx_int_t +ngx_http_lua_subrequest(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags) +{ + ngx_time_t *tp; + ngx_connection_t *c; + ngx_http_request_t *sr; + ngx_http_core_srv_conf_t *cscf; +#if 0 + ngx_http_postponed_request_t *pr, *p; +#endif + + r->main->subrequests--; + + if (r->main->subrequests == 0) { +#if defined(NGX_DTRACE) && NGX_DTRACE + ngx_http_probe_subrequest_cycle(r, uri, args); +#endif + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "subrequests cycle while processing \"%V\"", uri); + r->main->subrequests = 1; + return NGX_ERROR; + } + + sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t)); + if (sr == NULL) { + return NGX_ERROR; + } + + sr->signature = NGX_HTTP_MODULE; + + c = r->connection; + sr->connection = c; + + sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); + if (sr->ctx == NULL) { + return NGX_ERROR; + } + + if (ngx_list_init(&sr->headers_out.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + sr->main_conf = cscf->ctx->main_conf; + sr->srv_conf = cscf->ctx->srv_conf; + sr->loc_conf = cscf->ctx->loc_conf; + + sr->pool = r->pool; + + sr->headers_in = r->headers_in; + + ngx_http_clear_content_length(sr); + ngx_http_clear_accept_ranges(sr); + ngx_http_clear_last_modified(sr); + + sr->request_body = r->request_body; + + sr->content_length_n = -1; + + sr->method = NGX_HTTP_GET; + sr->http_version = r->http_version; + + sr->request_line = r->request_line; + sr->uri = *uri; + + if (args) { + sr->args = *args; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http subrequest \"%V?%V\"", uri, &sr->args); + + sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0; + sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0; + + sr->unparsed_uri = r->unparsed_uri; + sr->method_name = ngx_http_core_get_method; + sr->http_protocol = r->http_protocol; + + ngx_http_set_exten(sr); + + sr->main = r->main; + sr->parent = r; + sr->post_subrequest = ps; + sr->read_event_handler = ngx_http_request_empty_handler; + sr->write_event_handler = ngx_http_handler; + + if (c->data == r && r->postponed == NULL) { + c->data = sr; + } + + sr->variables = r->variables; + + sr->log_handler = r->log_handler; + +#if 0 + pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } + + pr->request = sr; + pr->out = NULL; + pr->next = NULL; + + if (r->postponed) { + for (p = r->postponed; p->next; p = p->next) { /* void */ } + p->next = pr; + + } else { + r->postponed = pr; + } +#endif + + sr->internal = 1; + + sr->discard_body = r->discard_body; + sr->expect_tested = 1; + sr->main_filter_need_in_memory = r->main_filter_need_in_memory; + + sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; + + tp = ngx_timeofday(); + sr->start_sec = tp->sec; + sr->start_msec = tp->msec; + + r->main->count++; + + *psr = sr; + +#if defined(NGX_DTRACE) && NGX_DTRACE + ngx_http_probe_subrequest_start(sr); +#endif + + return ngx_http_post_request(sr, NULL); +} + diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index ede8b13017..2d3978219a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1236,29 +1236,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua waiting for pending subrequests"); - if (r == c->data && r->postponed) { - if (r->postponed->request) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua activating the next postponed request %V?%V", - &r->postponed->request->uri, - &r->postponed->request->args); - - c->data = r->postponed->request; - -#if defined(nginx_version) && nginx_version >= 8012 - ngx_http_post_request(r->postponed->request, NULL); -#else - ngx_http_post_request(r->postponed->request); -#endif - - } else { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua flushing postponed output"); - - ngx_http_lua_flush_postponed_outputs(r); - } - } - return NGX_DONE; } @@ -1444,9 +1421,11 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "useless lua write event handler"); +#if 0 if (ctx->entered_content_phase) { ngx_http_finalize_request(r, NGX_DONE); } +#endif return NGX_OK; From 3b6f584be34649462bfd3c06c933134885e294de Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 29 Aug 2012 20:16:48 -0700 Subject: [PATCH 0008/2239] tweaked a test case to make it less possible to fail in slow testing modes. --- t/023-rewrite/sleep.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index 2f8255e1d3..5ee531b9dc 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -33,7 +33,7 @@ __DATA__ --- request GET /test --- response_body_like chop -^0\.(?:4[5-9]\d*|5[0-5]\d*|5)$ +^0\.(?:4[5-9]\d*|5[0-9]\d*|5)$ --- error_log lua ready to sleep for lua sleep handler: "/test?" From 3a90b574080d1e9a83a636af5e74a8182365cd09 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 30 Aug 2012 11:48:21 -0700 Subject: [PATCH 0009/2239] bugfix: we did not compile with nginx cores without the allow_request_body_updating patch. thanks Dirk Feytons. --- src/ngx_http_lua_subrequest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 18983e6fae..d1e5afaf87 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1314,7 +1314,9 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->request_body = r->request_body; +#ifdef HAVE_ALLOW_REQUEST_BODY_UPDATING_PATCH sr->content_length_n = -1; +#endif sr->method = NGX_HTTP_GET; sr->http_version = r->http_version; From 75c8c30980de86bb0fbc219550c933691e8454a0 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Sep 2012 16:15:40 -0700 Subject: [PATCH 0010/2239] updated valgrind.suppress for i386. --- valgrind.suppress | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/valgrind.suppress b/valgrind.suppress index 21e39ad99c..eef8401b96 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,5 +1,11 @@ { +Memcheck:Leak +fun:malloc +fun:ngx_alloc +} +{ + Memcheck:Addr1 fun:ngx_init_cycle fun:ngx_master_process_cycle From 9728454afd03be17fa55563da1a777f5f6e67ad3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Sep 2012 17:39:03 -0700 Subject: [PATCH 0011/2239] bugfix: the main request might be prematurely terminated if a subrequest issued by ngx.location.capture (or its friends) was finalized with error codes. --- src/ngx_http_lua_subrequest.c | 4 ++-- t/020-subrequest.t | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index d1e5afaf87..81bd8ab69b 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -835,7 +835,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) ctx = psr_data->ctx; if (ctx->run_post_subrequest) { - return rc; + return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -947,7 +947,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) r->connection->data = r; } - return rc; + return NGX_OK; } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 95e72c33d1..aa95ba124c 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1071,3 +1071,47 @@ r%5b%5d=http%3a%2f%2fajax.googleapis.com%3a80%2fajax%2flibs%2fjquery%2f1.7.2%2fj --- no_error_log [error] + + +=== TEST 41: subrequests finalized with NGX_ERROR +--- config + location /sub { + content_by_lua ' + ngx.exit(ngx.ERROR) + '; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/sub") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- response_body +status: 500 +body: + + + +=== TEST 42: subrequests finalized with 500 +--- config + location /sub { + return 500; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/sub") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- response_body +status: 500 +body: + From 46a3c3d5245db1ec88d64ea99763e8c9f5c6c74f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Sep 2012 17:40:19 -0700 Subject: [PATCH 0012/2239] updated .gitignore a bit. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a316fe18a9..261a7fc03a 100644 --- a/.gitignore +++ b/.gitignore @@ -151,3 +151,4 @@ src/probe.h *.plist lua Makefile +tsubreq From 865cb1981bec22520b4541db0ffdb2a185f0fb91 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Sep 2012 21:47:13 -0700 Subject: [PATCH 0013/2239] added a (passing) test for returning NGX_ERROR in the output body filter for the subrequest issued by ngx.location.capture(). --- src/ngx_http_lua_subrequest.c | 1 + t/020-subrequest.t | 48 +++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 81bd8ab69b..dbf9850255 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -947,6 +947,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) r->connection->data = r; } + dd("returning OK"); return NGX_OK; } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index aa95ba124c..6de4844c4f 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -3,14 +3,14 @@ use lib 'lib'; use Test::Nginx::Socket; #master_on(); -workers(1); +#workers(1); #worker_connections(1014); #log_level('warn'); #master_process_enabled(1); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 10); +plan tests => repeat_each() * (blocks() * 2 + 11); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -1115,3 +1115,47 @@ GET /main status: 500 body: + + +=== TEST 43: subrequests with an output body filter returning NGX_ERROR +--- config + location /sub { + echo hello world; + body_filter_by_lua ' + return ngx.ERROR + '; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/sub") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- stap2 +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +--- response_body +--- error_code +--- no_error_log +[error] + From c56a98cd8085aab5500735d85ef6eaf9e8378eaa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Sep 2012 22:11:33 -0700 Subject: [PATCH 0014/2239] bugfix: we should not always return NGX_OK in our post_subrequest handler even if rc >= 300 because it will prevent response headers from being sent. --- src/ngx_http_lua_subrequest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index dbf9850255..d515b95e1f 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -947,8 +947,11 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) r->connection->data = r; } - dd("returning OK"); - return NGX_OK; + if (rc == NGX_ERROR) { + return NGX_OK; + } + + return rc; } From d06e260181bff144ba5705e5c8470a4df437ce0f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 7 Sep 2012 14:32:09 -0700 Subject: [PATCH 0015/2239] made a test case requires DNS resolving less possible to fail in slow testing modes. --- t/091-coroutine.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/091-coroutine.t b/t/091-coroutine.t index bd83d0b4b6..0c907daf4c 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -209,6 +209,7 @@ successfully connected to: openresty.org *** All Done *** --- no_error_log [error] +--- timeout: 10 From b3255acdaebbb5f4aa417e07b5b6fd9e44301154 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Sep 2012 22:37:55 -0700 Subject: [PATCH 0016/2239] bugfix: reset the subrequest status code when the non-buffered ngx_http_upstream request in the subrequest fails due to timeout errors or premature connection close and etc. this requires the patch for the nginx core to fix an issue in ngx_http_upstream: https://raw.github.com/agentzh/ngx_openresty/master/patches/nginx-1.2.3-nonbuffered-upstream-truncation.patch --- src/ngx_http_lua_subrequest.c | 4 ++ t/020-subrequest.t | 120 +++++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index d515b95e1f..8a92d9a1a1 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -880,6 +880,10 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; } + if (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE) { + pr_coctx->sr_statuses[ctx->index] = r->headers_out.status; + } + if (pr_coctx->sr_statuses[ctx->index] == 0) { pr_coctx->sr_statuses[ctx->index] = NGX_HTTP_OK; } diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 6de4844c4f..bd51fe5551 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -10,12 +10,12 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 11); +plan tests => repeat_each() * (blocks() * 2 + 15); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; #no_diff(); -#no_long_string(); +no_long_string(); #no_shuffle(); run_tests(); @@ -1159,3 +1159,119 @@ F(ngx_http_finalize_request) { --- no_error_log [error] + + +=== TEST 44: subrequests truncated in its response body due to premature connection close +--- config + location /memc { + internal; + + set $memc_key 'foo'; + #set $memc_exptime 300; + memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/memc") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19112 +--- tcp_reply eval +"VALUE foo 0 1024\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +upstream fin req: error=0 eof=1 rc=502 +post subreq: rc=0, status=502 + +--- response_body +status: 502 +body: hello world +--- no_error_log +[error] + + + +=== TEST 45: subrequests truncated in its response body due to upstream read timeout +--- config + memc_read_timeout 100ms; + location /memc { + internal; + + set $memc_key 'foo'; + #set $memc_exptime 300; + memc_pass 127.0.0.1:19112; #$TEST_NGINX_MEMCACHED_PORT; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/memc") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19112 +--- tcp_no_close +--- tcp_reply eval +"VALUE foo 0 1024\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +conn err: 110: upstream timed out +upstream fin req: error=0 eof=0 rc=504 +post subreq: rc=0, status=504 + +--- response_body +status: 504 +body: hello world + +--- error_log +upstream timed out + From 73faa581d8ee0d6dde0ecaf29635a2f433d96ffa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 9 Sep 2012 12:57:35 -0700 Subject: [PATCH 0017/2239] added more tests for bad upstream in subrequests. --- .gitignore | 1 + t/020-subrequest.t | 410 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 408 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 261a7fc03a..2c6a20aea5 100644 --- a/.gitignore +++ b/.gitignore @@ -152,3 +152,4 @@ src/probe.h lua Makefile tsubreq +addr2line diff --git a/t/020-subrequest.t b/t/020-subrequest.t index bd51fe5551..3532349324 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() * 2 + 15); +plan tests => repeat_each() * (blocks() * 3 + 6); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -41,6 +41,8 @@ __DATA__ GET /lua --- response_body DELETE +--- no_error_log +[error] @@ -67,6 +69,8 @@ DELETE GET /lua --- response_body DELETE +--- no_error_log +[error] @@ -93,6 +97,8 @@ DELETE GET /lua --- response_body POST +--- no_error_log +[error] @@ -115,6 +121,8 @@ POST GET /lua --- response_body HEAD +--- no_error_log +[error] @@ -141,6 +149,8 @@ HEAD GET /lua --- response_body GET +--- no_error_log +[error] @@ -166,6 +176,8 @@ GET GET /lua --- response_body GET +--- no_error_log +[error] @@ -191,6 +203,8 @@ GET GET /lua --- response_body GET +--- no_error_log +[error] @@ -221,6 +235,8 @@ GET /lua --- response_body chomp PUT hello +--- no_error_log +[error] @@ -248,6 +264,8 @@ GET /lua --- response_body chomp PUT hello +--- no_error_log +[error] @@ -288,6 +306,8 @@ PUT hello GET [] +--- no_error_log +[error] @@ -318,6 +338,8 @@ GET /lua --- response_body chomp POST hello +--- no_error_log +[error] @@ -356,6 +378,8 @@ GET /lua GET: 404 PUT: 201 cached: hello +--- no_error_log +[error] @@ -396,6 +420,8 @@ GET /lua GET: 404 PUT: 201 cached: hello +--- no_error_log +[error] @@ -415,6 +441,8 @@ cached: hello --- request GET /lua --- response_body eval: "\n" +--- no_error_log +[error] @@ -435,6 +463,8 @@ GET /lua GET /lua --- response_body fo%3d=%3d%3e +--- no_error_log +[error] @@ -458,6 +488,8 @@ GET /lua ^(?:fo%3d=%3d%3e\&%3d=%3a|%3d=%3a\&fo%3d=%3d%3e)$ --- no_error_log [error] +--- no_error_log +[error] @@ -479,6 +511,8 @@ GET /lua GET /lua --- response_body_like chop ^(?:bar=hello\&foo=3|foo=3\&bar=hello)$ +--- no_error_log +[error] @@ -499,6 +533,8 @@ GET /lua GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 +--- error_log +attempt to use a non-string key in the "args" option table @@ -519,6 +555,8 @@ GET /lua GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 +--- error_log +attempt to use a non-string key in the "args" option table @@ -539,6 +577,8 @@ GET /lua GET /lua --- response_body a=3&b=4 +--- no_error_log +[error] @@ -559,6 +599,8 @@ a=3&b=4 GET /lua --- response_body a=3&b=4 +--- no_error_log +[error] @@ -577,6 +619,8 @@ a=3&b=4 GET /lua --- response_body main req +--- no_error_log +[error] @@ -599,6 +643,8 @@ main req GET /main --- response_body sub req +--- no_error_log +[error] @@ -622,6 +668,8 @@ sub req GET /main --- response_body sub req +--- no_error_log +[error] @@ -646,6 +694,8 @@ GET /lua Foo: bar --- response_body header foo: [bar] +--- no_error_log +[error] @@ -670,6 +720,8 @@ GET /lua Foo: bar --- response_body header foo: [bar] +--- no_error_log +[error] @@ -705,6 +757,8 @@ hello, b hello, c --- error_log lua reuse free buf memory +--- no_error_log +[error] @@ -736,6 +790,8 @@ hi --- response_body chomp POST hello +--- no_error_log +[error] @@ -759,6 +815,8 @@ hello, static file ^200 [A-Za-z]+, \d{1,2} [A-Za-z]+ \d{4} \d{2}:\d{2}:\d{2} GMT hello, static file$ +--- no_error_log +[error] @@ -783,6 +841,8 @@ GET /lua --- response_body bar nil +--- no_error_log +[error] @@ -803,6 +863,8 @@ nil GET /lua --- response_body bar +--- no_error_log +[error] @@ -1161,7 +1223,7 @@ F(ngx_http_finalize_request) { -=== TEST 44: subrequests truncated in its response body due to premature connection close +=== TEST 44: subrequests truncated in its response body due to premature connection close (nonbuffered) --- config location /memc { internal; @@ -1217,7 +1279,7 @@ body: hello world -=== TEST 45: subrequests truncated in its response body due to upstream read timeout +=== TEST 45: subrequests truncated in its response body due to upstream read timeout (nonbuffered) --- config memc_read_timeout 100ms; location /memc { @@ -1275,3 +1337,345 @@ body: hello world --- error_log upstream timed out + + +=== TEST 46: subrequests truncated in its response body due to premature connection close (buffered) +--- config + location /proxy { + internal; + + proxy_read_timeout 100ms; + proxy_buffering on; + proxy_pass http://127.0.0.1:19113; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/proxy") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_reply eval +"HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +upstream fin req: error=0 eof=1 rc=502 +post subreq: rc=0, status=502 + +--- response_body +status: 502 +body: hello world +--- no_error_log +[error] + + + +=== TEST 47: subrequests truncated in its response body due to read timeout (buffered) +--- config + location /proxy { + internal; + + proxy_read_timeout 100ms; + proxy_buffering on; + proxy_pass http://127.0.0.1:19113; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/proxy") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_no_close +--- tcp_reply eval +"HTTP/1.0 200 OK\r\nContent-Length: 1024\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +conn err: 110: upstream timed out +upstream fin req: error=0 eof=0 rc=502 +post subreq: rc=0, status=502 + +--- response_body +status: 502 +body: +--- error_log +upstream timed out + + + +=== TEST 48: subrequests truncated in its response body due to premature connection close (buffered, no content-length) +--- config + location /proxy { + internal; + + proxy_read_timeout 100ms; + proxy_buffering on; + proxy_pass http://127.0.0.1:19113; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/proxy") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_reply eval +"HTTP/1.0 200 OK\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +upstream fin req: error=0 eof=1 rc=0 +post subreq: rc=0, status=200 + +--- response_body +status: 200 +body: hello world +--- no_error_log +[error] + + + +=== TEST 49: subrequests truncated in its response body due to read timeout (buffered, no content-length) +--- config + location /proxy { + internal; + + proxy_read_timeout 100ms; + proxy_buffering on; + proxy_pass http://127.0.0.1:19113; + } + + location /main { + content_by_lua ' + res = ngx.location.capture("/proxy") + ngx.say("status: ", res.status) + ngx.say("body: ", res.body) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_no_close +--- tcp_reply eval +"HTTP/1.0 200 OK\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +conn err: 110: upstream timed out +upstream fin req: error=0 eof=0 rc=502 +post subreq: rc=0, status=502 + +--- response_body +status: 502 +body: +--- error_log +upstream timed out + + + +=== TEST 50: subrequests truncated in its response body due to premature connection close (nonbuffered, no content-length) +--- config + 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) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_reply eval +"HTTP/1.0 200 OK\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +upstream fin req: error=0 eof=1 rc=0 +post subreq: rc=0, status=200 + +--- response_body +status: 200 +body: hello world +--- no_error_log +[error] + + + +=== TEST 51: subrequests truncated in its response body due to read timeout (nonbuffered, no content-length) +--- config + location /proxy { + internal; + + proxy_read_timeout 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) + '; + } +--- request +GET /main +--- tcp_listen: 19113 +--- tcp_no_close +--- tcp_reply eval +"HTTP/1.0 200 OK\r\n\r\nhello world" + +--- stap +F(ngx_http_upstream_finalize_request) { + printf("upstream fin req: error=%d eof=%d rc=%d\n", + $r->upstream->peer->connection->read->error, + $r->upstream->peer->connection->read->eof, + $rc) + #print_ubacktrace() +} +F(ngx_connection_error) { + printf("conn err: %d: %s\n", $err, user_string($text)) + #print_ubacktrace() +} +F(ngx_http_lua_post_subrequest) { + printf("post subreq: rc=%d, status=%d\n", $rc, $r->headers_out->status) + #print_ubacktrace() +} +/* +F(ngx_http_finalize_request) { + printf("finalize: %d\n", $rc) +} +*/ +--- stap_out +conn err: 110: upstream timed out +upstream fin req: error=0 eof=0 rc=504 +post subreq: rc=0, status=504 + +--- response_body +status: 504 +body: hello world +--- error_log +upstream timed out + From e572d87726a84e44b71c70ecca8d6af1bd1c9dc4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 9 Sep 2012 16:01:24 -0700 Subject: [PATCH 0018/2239] fixed the test cases for the mockeagain (W) testing mode. --- t/020-subrequest.t | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 3532349324..9ae7d11bc6 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 + 6); +plan tests => repeat_each() * (blocks() * 3 + 10); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -1225,6 +1225,7 @@ F(ngx_http_finalize_request) { === TEST 44: subrequests truncated in its response body due to premature connection close (nonbuffered) --- config + server_tokens off; location /memc { internal; @@ -1243,6 +1244,7 @@ F(ngx_http_finalize_request) { --- request GET /main --- tcp_listen: 19112 +--- tcp_query_len: 9 --- tcp_reply eval "VALUE foo 0 1024\r\nhello world" @@ -1341,6 +1343,8 @@ upstream timed out === TEST 46: subrequests truncated in its response body due to premature connection close (buffered) --- config + server_tokens off; + location /proxy { internal; @@ -1359,6 +1363,7 @@ upstream timed out --- 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" @@ -1455,6 +1460,7 @@ upstream timed out === TEST 48: subrequests truncated in its response body due to premature connection close (buffered, no content-length) --- config + server_tokens off; location /proxy { internal; @@ -1473,6 +1479,7 @@ upstream timed out --- request GET /main --- tcp_listen: 19113 +--- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" @@ -1569,6 +1576,8 @@ upstream timed out === TEST 50: subrequests truncated in its response body due to premature connection close (nonbuffered, no content-length) --- config + server_tokens off; + location /proxy { internal; @@ -1587,6 +1596,7 @@ upstream timed out --- request GET /main --- tcp_listen: 19113 +--- tcp_query_len: 65 --- tcp_reply eval "HTTP/1.0 200 OK\r\n\r\nhello world" From a7d6962c21f52af1d3b7a02daa69e64c73634537 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 9 Sep 2012 21:30:41 -0700 Subject: [PATCH 0019/2239] upgraded version to 0.6.4. --- README | 6 +++--- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README b/README index 24350f45a7..56562e5e7e 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.6.3 - () released on 25 - August 2012. + This document describes ngx_lua v0.6.4 + () released on 9 + September 2012. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): diff --git a/README.markdown b/README.markdown index 955668e6be..2a7ab32d51 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.6.3](https://github.com/chaoslawful/lua-nginx-module/tags) released on 25 August 2012. +This document describes ngx_lua [v0.6.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 September 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 2486e8b6ba..b7fc814cea 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.6.3] released on 25 August 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.4] released on 9 September 2012. = Synopsis = From 9fe21af577ec9109eda6a80be684964ac683cfc5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 00:59:14 -0700 Subject: [PATCH 0020/2239] use google.com instead of taobao.com in the test suite. --- t/016-resp-header.t | 4 ++-- t/022-redirect.t | 18 +++++++++--------- t/030-uri-args.t | 4 ++-- t/058-tcp-socket.t | 2 +- t/065-tcp-socket-timeout.t | 10 +++++----- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 78420092c6..7a1a5efdf1 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -74,13 +74,13 @@ Hel location /read { content_by_lua ' ngx.status = 302; - ngx.header["Location"] = "http://www.taobao.com/foo"; + ngx.header["Location"] = "http://google.com/foo"; '; } --- request GET /read --- response_headers -Location: http://www.taobao.com/foo +Location: http://google.com/foo --- response_body --- error_code: 302 diff --git a/t/022-redirect.t b/t/022-redirect.t index 44478c7e60..54b903e4a1 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -26,14 +26,14 @@ __DATA__ --- config location /read { content_by_lua ' - ngx.redirect("http://www.taobao.com/foo"); + ngx.redirect("http://google.com/foo"); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://www.taobao.com/foo +Location: http://google.com/foo --- response_body_like: 302 Found --- error_code: 302 @@ -43,14 +43,14 @@ Location: http://www.taobao.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_TEMPORARILY); + ngx.redirect("http://google.com/foo", ngx.HTTP_MOVED_TEMPORARILY); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://www.taobao.com/foo +Location: http://google.com/foo --- response_body_like: 302 Found --- error_code: 302 @@ -60,14 +60,14 @@ Location: http://www.taobao.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_PERMANENTLY); + ngx.redirect("http://google.com/foo", ngx.HTTP_MOVED_PERMANENTLY); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://www.taobao.com/foo +Location: http://google.com/foo --- response_body_like: 301 Moved Permanently --- error_code: 301 @@ -77,7 +77,7 @@ Location: http://www.taobao.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://www.taobao.com/foo", 404); + ngx.redirect("http://google.com/foo", 404); ngx.say("hi") '; } @@ -134,14 +134,14 @@ GET /read --- config location /read { content_by_lua ' - ngx.redirect("http://www.taobao.com/foo?bar=3"); + ngx.redirect("http://google.com/foo?bar=3"); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://www.taobao.com/foo?bar=3 +Location: http://google.com/foo?bar=3 --- response_body_like: 302 Found --- error_code: 302 diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 635769d500..dc2f8579c2 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -359,7 +359,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://www.taobao.com:5678; + proxy_pass http://google.com:5678; } --- request GET /foo?world @@ -498,7 +498,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://www.taobao.com:5678; + proxy_pass http://google.com:5678; } --- request GET /foo?world diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 4919e21f79..a0614c6c7f 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -297,7 +297,7 @@ connect() failed (111: Connection refused) location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("taobao.com", 16787) + local ok, err = sock:connect("google.com", 16787) ngx.say("connect: ", ok, " ", err) local bytes diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 4f35de43de..8bc070ad8c 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -43,7 +43,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -71,7 +71,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -99,7 +99,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -127,7 +127,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -156,7 +156,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return From 85c658475af9fba9a19e3b97d84d562a476a94f0 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 01:03:44 -0700 Subject: [PATCH 0021/2239] made the new subrequest test cases less possible to fail unexpectedly on slow machines. --- t/020-subrequest.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 9ae7d11bc6..23bb2f3293 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1348,7 +1348,7 @@ upstream timed out location /proxy { internal; - proxy_read_timeout 100ms; + #proxy_read_timeout 100ms; proxy_buffering on; proxy_pass http://127.0.0.1:19113; } @@ -1581,7 +1581,7 @@ upstream timed out location /proxy { internal; - proxy_read_timeout 100ms; + #proxy_read_timeout 100ms; proxy_buffering off; proxy_pass http://127.0.0.1:19113; } @@ -1638,7 +1638,7 @@ body: hello world location /proxy { internal; - proxy_read_timeout 100ms; + proxy_read_timeout 500ms; proxy_buffering off; proxy_pass http://127.0.0.1:19113; } From 4abd896cd58529a6195339b230a71a2a4d08238c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 12:05:49 -0700 Subject: [PATCH 0022/2239] fixed a test case in 020-subrequest.t for slow machines. --- t/020-subrequest.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 23bb2f3293..9b463ad4cd 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1332,9 +1332,9 @@ conn err: 110: upstream timed out upstream fin req: error=0 eof=0 rc=504 post subreq: rc=0, status=504 ---- response_body -status: 504 -body: hello world +--- response_body_like chop +^status: 504 +body: --- error_log upstream timed out From 7134d428a740b7c6702cde830de1ae3eb3e6247b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 15:23:12 -0700 Subject: [PATCH 0023/2239] refactor: made ngx.sleep() schedule itself at the coroutine level. --- src/ngx_http_lua_accessby.c | 11 ++----- src/ngx_http_lua_bodyfilterby.c | 11 ++----- src/ngx_http_lua_common.h | 2 ++ src/ngx_http_lua_contentby.c | 20 ++--------- src/ngx_http_lua_headerfilterby.c | 11 ++----- src/ngx_http_lua_logby.c | 11 ++----- src/ngx_http_lua_req_body.c | 2 +- src/ngx_http_lua_rewriteby.c | 11 ++----- src/ngx_http_lua_setby.c | 9 +---- src/ngx_http_lua_sleep.c | 55 ++++++++++++++++++++++++++++--- src/ngx_http_lua_util.c | 23 ++----------- src/ngx_http_lua_util.h | 19 +++++++++++ 12 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index c3ea63fdfc..88d1543279 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -80,17 +80,10 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } dd("entered? %d", (int) ctx->entered_access_phase); @@ -102,7 +95,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) if (ctx->entered_access_phase) { dd("calling wev handler"); - rc = ngx_http_lua_wev_handler(r); + rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); return rc; diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index c62aedfcff..40e0e927ec 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -278,17 +278,10 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } - - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } if (ctx->cleanup == NULL) { diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 098d19166e..4b973ab709 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -251,6 +251,8 @@ typedef struct ngx_http_lua_ctx_s { (or running phase) for the current Lua chunk */ + ngx_http_handler_pt resume_handler; + lua_State *cur_co; /* the current running Lua coroutine, not necessarily to be the request's entry coroutine */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index a271ffeed8..8e5bf84f38 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -28,18 +28,11 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - dd("setting new ctx, ctx = %p, size: %d", ctx, (int) sizeof(*ctx)); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); - } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); @@ -124,17 +117,10 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - - dd("setting new ctx: ctx = %p, size: %d", ctx, (int) sizeof(*ctx)); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } dd("entered? %d", (int) ctx->entered_content_phase); @@ -145,7 +131,7 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) if (ctx->entered_content_phase) { dd("calling wev handler"); - rc = ngx_http_lua_wev_handler(r); + rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); return rc; } diff --git a/src/ngx_http_lua_headerfilterby.c b/src/ngx_http_lua_headerfilterby.c index b6bf61ea7e..683ef01381 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -261,17 +261,10 @@ ngx_http_lua_header_filter(ngx_http_request_t *r) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } - - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } if (ctx->cleanup == NULL) { diff --git a/src/ngx_http_lua_logby.c b/src/ngx_http_lua_logby.c index 4ba1fd93cf..d0773d5595 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -83,17 +83,10 @@ ngx_http_lua_log_handler(ngx_http_request_t *r) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } - - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 7543a22df2..53f503bae6 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -154,7 +154,7 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) ctx->waiting_more_body = 0; if (ctx->entered_content_phase) { - ngx_http_lua_wev_handler(r); + (void) ctx->resume_handler(r); } else { ngx_http_core_run_phases(r); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 3ecc0b6b3d..78c09df403 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -83,17 +83,10 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) dd("ctx = %p", ctx); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } dd("entered? %d", (int) ctx->entered_rewrite_phase); @@ -104,7 +97,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) if (ctx->entered_rewrite_phase) { dd("rewriteby: calling wev handler"); - rc = ngx_http_lua_wev_handler(r); + rc = ctx->resume_handler(r); dd("rewriteby: wev handler returns %d", (int) rc); if (rc == NGX_OK) { diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 88d23582e3..49d8b04570 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -50,18 +50,11 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } - dd("setting new ctx: ctx = %p", ctx); - - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - - ngx_http_set_ctx(r, ctx, ngx_http_lua_module); - } else { ngx_http_lua_reset_ctx(r, L, ctx); } diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index f92129f97b..227f734842 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -11,6 +11,7 @@ static int ngx_http_lua_ngx_sleep(lua_State *L); static void ngx_http_lua_sleep_handler(ngx_event_t *ev); static void ngx_http_lua_co_cleanup(void *data); +static ngx_int_t ngx_http_lua_sleep_resume(ngx_http_request_t *r); static int @@ -55,8 +56,10 @@ ngx_http_lua_ngx_sleep(lua_State *L) return luaL_error(L, "no co ctx found"); } + coctx->data = r; + coctx->sleep.handler = ngx_http_lua_sleep_handler; - coctx->sleep.data = r; + coctx->sleep.data = coctx; coctx->sleep.log = r->connection->log; dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, @@ -96,7 +99,9 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_http_log_ctx_t *log_ctx; ngx_http_lua_co_ctx_t *coctx; - r = ev->data; + coctx = ev->data; + + r = coctx->data; c = r->connection; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -111,8 +116,6 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep handler: \"%V?%V\"", &r->uri, &r->args); - coctx = ctx->cur_co_ctx; - if (!coctx->sleep.timedout) { dd("reach lua sleep event handler without timeout!"); return; @@ -126,10 +129,14 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_del_timer(&coctx->sleep); } + ctx->cur_co_ctx = coctx; + ctx->cur_co = coctx->co; + if (ctx->entered_content_phase) { - ngx_http_lua_wev_handler(r); + (void) ngx_http_lua_sleep_resume(r); } else { + ctx->resume_handler = ngx_http_lua_sleep_resume; ngx_http_core_run_phases(r); } @@ -162,3 +169,41 @@ ngx_http_lua_co_cleanup(void *data) } } + +static ngx_int_t +ngx_http_lua_sleep_resume(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_main_conf_t *lmcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + r->write_event_handler = ngx_http_core_run_phases; + + return rc; +} + diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 2d3978219a..6e005e4f74 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -701,6 +701,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->exit_code = 0; ctx->exited = 0; + ctx->resume_handler = ngx_http_lua_wev_handler; ngx_str_null(&ctx->exec_uri); ngx_str_null(&ctx->exec_args); @@ -1160,7 +1161,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) c = r->connection; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua run write event handler"); + "lua run write event handler"); wev = c->write; @@ -1306,24 +1307,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (coctx->sleep.timer_set) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua still waiting for a sleep timer: \"%V?%V\"", - &r->uri, &r->args); - - if (wev->ready) { - ngx_handle_write_event(wev, 0); - } - - return NGX_DONE; - } - - if (coctx->sleep.timedout) { - coctx->sleep.timedout = 0; - nret = 0; - goto run; - } - if (coctx->socket_busy && !coctx->socket_ready) { return NGX_DONE; } @@ -1419,7 +1402,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "useless lua write event handler"); + "useless lua write event handler"); #if 0 if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 6f9fbfe73c..3413a97518 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -127,5 +127,24 @@ ngx_http_lua_co_ctx_t * ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); +static ngx_inline ngx_http_lua_ctx_t * +ngx_http_lua_create_ctx(ngx_http_request_t *r) +{ + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ctx->entry_ref = LUA_NOREF; + ctx->ctx_ref = LUA_NOREF; + ctx->resume_handler = ngx_http_lua_wev_handler; + + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + return ctx; +} + + #endif /* NGX_HTTP_LUA_UTIL_H */ From 27dd2bab82d83b6951cc2542fb7cdae23d149684 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 15:44:09 -0700 Subject: [PATCH 0024/2239] minor cleanup in ngx.sleep(). --- src/ngx_http_lua_sleep.c | 5 ----- src/ngx_http_lua_subrequest.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 227f734842..2969493edd 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -81,11 +81,6 @@ ngx_http_lua_ngx_sleep(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); - if (ctx->entered_content_phase) { - dd("set write event handler"); - r->write_event_handler = ngx_http_lua_content_wev_handler; - } - return lua_yield(L, 0); } diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 8a92d9a1a1..cb32cec48f 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -519,7 +519,7 @@ 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); + extra_vars); if (rc != NGX_OK) { return luaL_error(L, "failed to adjust the subrequest: %d", From 2f884b83e0ba6d254d8d0f292b196698f7e4671f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Sep 2012 19:04:45 -0700 Subject: [PATCH 0025/2239] refactor: made ngx.location.capture() and ngx.location.capture_multi schedule themselves at the coroutine level (instead of the request level). --- dtrace/ngx_lua_provider.d | 2 + src/ngx_http_lua_common.h | 4 -- src/ngx_http_lua_contentby.c | 9 ++- src/ngx_http_lua_probe.h | 4 ++ src/ngx_http_lua_subrequest.c | 103 +++++++++++++++++++++++++++++++--- src/ngx_http_lua_subrequest.h | 2 - src/ngx_http_lua_util.c | 50 +++++------------ t/027-multi-capture.t | 47 +++++++++++++++- t/055-subreq-vars.t | 28 ++++++++- 9 files changed, 195 insertions(+), 54 deletions(-) diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index 22f76f1f20..c336b29e75 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -1,4 +1,6 @@ provider nginx_lua { + probe http__lua__info(char *s); + /* lua_State *L */ probe http__lua__register__preload__package(void *L, u_char *pkg); diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 4b973ab709..fd6d33f841 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -231,10 +231,6 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ - unsigned done:1; /* 1: subrequest is just done; - 0: subrequest is not done - yet or has already done */ - unsigned waiting_flush:1; /* for ngx.flush() */ unsigned socket_busy:1; /* for TCP */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 8e5bf84f38..1f7f162649 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -91,7 +91,14 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) void ngx_http_lua_content_wev_handler(ngx_http_request_t *r) { - (void) ngx_http_lua_wev_handler(r); + ngx_http_lua_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + (void) ctx->resume_handler(r); } diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index 6742eddccb..8fff85a1d5 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -17,6 +17,9 @@ #include +#define ngx_http_lua_probe_info(s) \ + NGINX_LUA_HTTP_LUA_INFO(s) + #define ngx_http_lua_probe_register_preload_package(L, pkg) \ NGINX_LUA_HTTP_LUA_REGISTER_PRELOAD_PACKAGE(L, pkg) @@ -46,6 +49,7 @@ #else /* !(NGX_DTRACE) */ +#define ngx_http_lua_probe_info(s) #define ngx_http_lua_probe_register_preload_package(L, pkg) #define ngx_http_lua_probe_req_socket_consume_preread(r, data, len) #define ngx_http_lua_probe_user_coroutine_create(r, parent, child) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index cb32cec48f..400d7c6d22 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -46,6 +46,10 @@ static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, ngx_http_post_subrequest_t *ps, ngx_uint_t flags); +static ngx_int_t ngx_http_lua_subrequest_resume(ngx_http_request_t *r); +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); /* ngx.location.capture is just a thin wrapper around @@ -169,7 +173,6 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) coctx->nsubreqs = nsubreqs; - coctx->done = 0; coctx->waiting = 0; extra_vars = NULL; @@ -522,8 +525,9 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) extra_vars); if (rc != NGX_OK) { + ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", - (int) rc); + (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); @@ -830,7 +834,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) u_char *p; ngx_chain_t *cl; - ngx_http_lua_post_subrequest_data_t *psr_data = data; + ngx_http_lua_post_subrequest_data_t *psr_data = data; ctx = psr_data->ctx; @@ -851,16 +855,19 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) } pr_coctx = psr_data->pr_co_ctx; - pr_coctx->waiting--; if (pr_coctx->waiting == 0) { - pr_coctx->done = 1; + dd("all subrequests are done"); + + pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; + pr_ctx->cur_co_ctx = pr_coctx; + pr_ctx->cur_co = pr_coctx->co; } if (pr_ctx->entered_content_phase) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua restoring write event handler"); + "lua restoring write event handler"); pr->write_event_handler = ngx_http_lua_content_wev_handler; } @@ -1059,9 +1066,9 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) } -void +static void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx) + ngx_http_lua_ctx_t *ctx) { ngx_uint_t i; ngx_uint_t index; @@ -1404,3 +1411,83 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, return ngx_http_post_request(sr, NULL); } + +static ngx_int_t +ngx_http_lua_subrequest_resume(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_main_conf_t *lmcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run subrequests done, resuming lua thread"); + + coctx = ctx->cur_co_ctx; + + dd("nsubreqs: %d", (int) coctx->nsubreqs); + + ngx_http_lua_handle_subreq_responses(r, ctx); + + dd("free sr_statues/headers/bodies memory ASAP"); + +#if 1 + ngx_pfree(r->pool, coctx->sr_statuses); + + coctx->sr_statuses = NULL; + coctx->sr_headers = NULL; + coctx->sr_bodies = NULL; +#endif + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, coctx->nsubreqs); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + r->write_event_handler = ngx_http_core_run_phases; + + return rc; +} + + +static void +ngx_http_lua_cancel_subreq(ngx_http_request_t *r) +{ + ngx_http_posted_request_t *pr; + ngx_http_posted_request_t **p; + +#if 1 + r->main->count--; + r->main->subrequests++; +#endif + + p = &r->main->posted_requests; + for (pr = r->main->posted_requests; pr->next; pr = pr->next) { + p = &pr->next; + } + + *p = NULL; + + r->connection->data = r->parent; +} + diff --git a/src/ngx_http_lua_subrequest.h b/src/ngx_http_lua_subrequest.h index 64f5512580..65ef2d4a99 100644 --- a/src/ngx_http_lua_subrequest.h +++ b/src/ngx_http_lua_subrequest.h @@ -6,8 +6,6 @@ void ngx_http_lua_inject_subrequest_api(lua_State *L); -void ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx); ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 6e005e4f74..507a6caa91 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1231,15 +1231,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } - dd("waiting: %d, done: %d", (int) coctx->waiting, coctx->done); - - if (coctx->waiting && !coctx->done) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua waiting for pending subrequests"); - - return NGX_DONE; - } - dd("req read body done: %d", (int) ctx->req_read_body_done); if (c->buffered) { @@ -1329,6 +1320,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } + /* ngx_http_lua_probe_info("udp cosocket hit"); */ + goto run; } @@ -1351,6 +1344,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } + /* ngx_http_lua_probe_info("tcp cosocket hit"); */ + goto run; } else if (coctx->waiting_flush) { @@ -1358,6 +1353,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) coctx->waiting_flush = 0; nret = 0; + /* ngx_http_lua_probe_info("waiting flush hit"); */ + goto run; } else if (ctx->req_read_body_done) { @@ -1371,32 +1368,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua read req body done, resuming lua thread"); - goto run; - - } else if (coctx->done) { - - coctx->done = 0; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua run subrequests done, resuming lua thread"); - - dd("nsubreqs: %d", (int) coctx->nsubreqs); - - ngx_http_lua_handle_subreq_responses(r, ctx); - - dd("free sr_statues/headers/bodies memory ASAP"); - -#if 1 - ngx_pfree(r->pool, coctx->sr_statuses); - - coctx->sr_statuses = NULL; - coctx->sr_headers = NULL; - coctx->sr_bodies = NULL; -#endif - - nret = coctx->nsubreqs; - - dd("location capture nret: %d", (int) nret); + /* ngx_http_lua_probe_info("req read body hit"); */ goto run; } @@ -1410,7 +1382,11 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } #endif - return NGX_OK; + if (ctx->entered_content_phase) { + return NGX_OK; + } + + return NGX_DONE; run: lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); @@ -1420,7 +1396,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua run thread returned %d", rc); + "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { return NGX_DONE; diff --git a/t/027-multi-capture.t b/t/027-multi-capture.t index 7ffa21604f..c649d99f2a 100644 --- a/t/027-multi-capture.t +++ b/t/027-multi-capture.t @@ -4,7 +4,6 @@ use lib 'lib'; use Test::Nginx::Socket; repeat_each(10); -#repeat_each(1); plan tests => repeat_each() * (blocks() * 2 + 2); @@ -657,6 +656,52 @@ content f: f } --- request GET /main +--- stap2 +global delta = " " + +M(http-subrequest-start) { + r = $arg1 + n = ngx_http_subreq_depth(r) + pr = ngx_http_req_parent(r) + printf("%sbegin %s -> %s (%d)\n", ngx_indent(n, delta), + ngx_http_req_uri(pr), + ngx_http_req_uri(r), + n) +} + +F(ngx_http_lua_run_thread) { + r = $r + uri = ngx_http_req_uri(r) + if (uri == "/main") { + printf("run thread %s: %d\n", uri, $nret) + #print_ubacktrace() + } +} + +M(http-lua-info) { + uri = ngx_http_req_uri($r) + #if (uri == "/main") { + printf("XXX info: %s: %s", uri, user_string($arg1)) + #} +} + +F(ngx_http_lua_post_subrequest) { + r = $r + n = ngx_http_subreq_depth(r) + pr = ngx_http_req_parent(r) + + printf("%send %s -> %s (%d)\n", ngx_indent(n, delta), + ngx_http_req_uri(r), + ngx_http_req_uri(pr), + n) +} + +F(ngx_http_lua_handle_subreq_responses) { + r = $r + n = ngx_http_subreq_depth(r) + printf("%shandle res %s (%d)\n", ngx_indent(n, delta), ngx_http_req_uri(r), n) +} + --- response_body rewrite a: a rewrite b: b diff --git a/t/055-subreq-vars.t b/t/055-subreq-vars.t index 4f10cb0f93..07e7d0591a 100644 --- a/t/055-subreq-vars.t +++ b/t/055-subreq-vars.t @@ -7,7 +7,6 @@ use Test::Nginx::Socket; #log_level('warn'); repeat_each(2); -#repeat_each(1); plan tests => repeat_each() * (blocks() * 2 + 5); @@ -36,6 +35,33 @@ __DATA__ ngx.print(res.body) '; } + +--- stap2 + +global delta = " " + +F(ngx_http_finalize_request) { + uri = ngx_http_req_uri($r) + printf("finalize req %s: %d\n", uri, $rc) + if ($rc == 500) { + print_ubacktrace() + } +} + +F(ngx_http_lua_run_thread) { + uri = ngx_http_req_uri($r) + printf("lua run thread %s\n", uri) +} + +M(http-subrequest-start) { + r = $arg1 + n = ngx_http_subreq_depth(r) + pr = ngx_http_req_parent(r) + printf("%sbegin %s -> %s (%d)\n", ngx_indent(n, delta), + ngx_http_req_uri(pr), + ngx_http_req_uri(r), + n) +} --- request GET /lua --- response_body_like: 500 Internal Server Error From e2f8b2a6b4fcacf7371f4dc24aeb910debe2a7a5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 12:14:00 -0700 Subject: [PATCH 0026/2239] enabled the http-lua-info static probes in ngx_http_lua_wev_handler. --- src/ngx_http_lua_util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 507a6caa91..0ff30bd30a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1320,7 +1320,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } - /* ngx_http_lua_probe_info("udp cosocket hit"); */ + ngx_http_lua_probe_info("udp cosocket hit"); goto run; } @@ -1344,7 +1344,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_DONE; } - /* ngx_http_lua_probe_info("tcp cosocket hit"); */ + ngx_http_lua_probe_info("tcp cosocket hit"); goto run; @@ -1353,7 +1353,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) coctx->waiting_flush = 0; nret = 0; - /* ngx_http_lua_probe_info("waiting flush hit"); */ + ngx_http_lua_probe_info("waiting flush hit"); goto run; @@ -1368,7 +1368,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua read req body done, resuming lua thread"); - /* ngx_http_lua_probe_info("req read body hit"); */ + ngx_http_lua_probe_info("req read body hit"); goto run; } From 9cb0d829d373b6fdfdd6b5585a7068cb11099b36 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 16:05:09 -0700 Subject: [PATCH 0027/2239] refactor: made TCP/stream cosockets schedule their I/O automatically on the Lua coroutine level. --- src/ngx_http_lua_common.h | 1 - src/ngx_http_lua_socket_tcp.c | 100 +++++++++++++++++++++++++++------- src/ngx_http_lua_socket_tcp.h | 2 + src/ngx_http_lua_util.c | 33 +---------- t/058-tcp-socket.t | 2 + 5 files changed, 88 insertions(+), 50 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index fd6d33f841..7a85e130d9 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -234,7 +234,6 @@ struct ngx_http_lua_co_ctx_s { unsigned waiting_flush:1; /* for ngx.flush() */ unsigned socket_busy:1; /* for TCP */ - unsigned socket_ready:1; /* for TCP */ unsigned udp_socket_busy:1; /* for UDP */ unsigned udp_socket_ready:1; /* for UDP */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 6e5b8d0bdb..829ccc71e2 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -89,6 +89,7 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); static ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r); +static ngx_int_t ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r); enum { @@ -557,6 +558,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) /* still resolving */ + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; @@ -564,7 +566,6 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) coctx->data = u; coctx->socket_busy = 1; - coctx->socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -699,10 +700,12 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->waiting = 0; if (waiting) { - coctx = lctx->cur_co_ctx; + coctx = u->co_ctx; coctx->socket_busy = 0; - coctx->socket_ready = 1; + + lctx->resume_handler = ngx_http_lua_socket_tcp_resume; + r->write_event_handler(r); } else { @@ -867,6 +870,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, r->write_event_handler = ngx_http_lua_content_wev_handler; } + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_connect_retval_handler; @@ -874,7 +878,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, coctx->data = u; coctx->socket_busy = 1; - coctx->socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -1118,6 +1121,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) r->write_event_handler = ngx_http_lua_content_wev_handler; } + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; @@ -1127,7 +1131,6 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) coctx->data = u; coctx->socket_busy = 1; - coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -1644,6 +1647,7 @@ ngx_http_lua_socket_tcp_send(lua_State *L) r->write_event_handler = ngx_http_lua_content_wev_handler; } + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_send_retval_handler; @@ -1653,7 +1657,6 @@ ngx_http_lua_socket_tcp_send(lua_State *L) coctx->data = u; coctx->socket_busy = 1; - coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -2024,16 +2027,15 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - coctx = ctx->cur_co_ctx; + coctx = u->co_ctx; + coctx->socket_busy = 0; - dd("setting socket_ready to 1"); - dd("prepare retvals: %p(%p), u:%p, ctx->data:%p", u->prepare_retvals, - ngx_http_lua_socket_tcp_receive_retval_handler, u, coctx->data); + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } - coctx->socket_busy = 0; - coctx->socket_ready = 1; + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2065,14 +2067,18 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - - coctx = ctx->cur_co_ctx; + coctx = u->co_ctx; dd("setting socket_ready to 1"); coctx->socket_busy = 0; - coctx->socket_ready = 1; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->resume_handler = ngx_http_lua_socket_tcp_resume; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2502,6 +2508,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) r->write_event_handler = ngx_http_lua_content_wev_handler; } + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_tcp_receive_retval_handler; @@ -2511,7 +2518,6 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) coctx->data = u; coctx->socket_busy = 1; - coctx->socket_ready = 0; return lua_yield(L, 0); } @@ -3820,3 +3826,59 @@ ngx_http_lua_test_expect(ngx_http_request_t *r) return NGX_ERROR; } + +static ngx_int_t +ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) +{ + int nret; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_main_conf_t *lmcf; + + ngx_http_lua_socket_tcp_upstream_t *u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run subrequests done, resuming lua thread"); + + coctx = ctx->cur_co_ctx; + + u = coctx->data; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket calling prepare retvals handler %p, " + "u:%p", u->prepare_retvals, u); + + nret = u->prepare_retvals(r, u, ctx->cur_co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index d5d0553d2f..f54c63b034 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -77,6 +77,8 @@ struct ngx_http_lua_socket_tcp_upstream_s { size_t request_len; ngx_chain_t *request_bufs; + ngx_http_lua_co_ctx_t *co_ctx; + ngx_uint_t reused; unsigned request_sent:1; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0ff30bd30a..564174db51 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1155,7 +1155,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_chain_t *cl; ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_tcp_upstream_t *tcp; ngx_http_lua_socket_udp_upstream_t *udp; c = r->connection; @@ -1298,10 +1297,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (coctx->socket_busy && !coctx->socket_ready) { - return NGX_DONE; - } - if (coctx->udp_socket_busy && !coctx->udp_socket_ready) { return NGX_DONE; } @@ -1325,30 +1320,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto run; } - if (!coctx->socket_busy && coctx->socket_ready) { - - dd("resuming socket api"); - - dd("setting socket_ready to 0"); - - coctx->socket_ready = 0; - - tcp = coctx->data; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua tcp socket calling prepare retvals handler %p, " - "u:%p", tcp->prepare_retvals, tcp); - - nret = tcp->prepare_retvals(r, tcp, ctx->cur_co); - if (nret == NGX_AGAIN) { - return NGX_DONE; - } - - ngx_http_lua_probe_info("tcp cosocket hit"); - - goto run; - - } else if (coctx->waiting_flush) { + if (coctx->waiting_flush) { coctx->waiting_flush = 0; nret = 0; @@ -1356,8 +1328,9 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_http_lua_probe_info("waiting flush hit"); goto run; + } - } else if (ctx->req_read_body_done) { + if (ctx->req_read_body_done) { dd("turned off req read body done"); diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index a0614c6c7f..82f314f362 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -71,6 +71,7 @@ __DATA__ content_by_lua 'ngx.say("foo")'; more_clear_headers Date; } + --- request GET /t --- response_body @@ -243,6 +244,7 @@ attempt to send data on a closed socket: end '; } + --- request GET /t --- response_body From b88aa3eaff7588dbea718f39db4470d300b6aa7f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 16:14:34 -0700 Subject: [PATCH 0028/2239] refactor: removed the unused "socket_busy" flag from ngx_http_lua_co_ctx_t. --- src/ngx_http_lua_common.h | 2 -- src/ngx_http_lua_socket_tcp.c | 22 ---------------------- 2 files changed, 24 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 7a85e130d9..86e27920e1 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -233,8 +233,6 @@ struct ngx_http_lua_co_ctx_s { unsigned waiting_flush:1; /* for ngx.flush() */ - unsigned socket_busy:1; /* for TCP */ - unsigned udp_socket_busy:1; /* for UDP */ unsigned udp_socket_ready:1; /* for UDP */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 829ccc71e2..88a038aa4a 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -565,7 +565,6 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) dd("setting data to %p", u); coctx->data = u; - coctx->socket_busy = 1; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -588,7 +587,6 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) struct sockaddr_in *sin; ngx_uint_t i; unsigned waiting; - ngx_http_lua_co_ctx_t *coctx; u = ctx->data; r = u->request; @@ -700,12 +698,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->waiting = 0; if (waiting) { - - coctx = u->co_ctx; - coctx->socket_busy = 0; - lctx->resume_handler = ngx_http_lua_socket_tcp_resume; - r->write_event_handler(r); } else { @@ -877,7 +870,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, dd("setting data to %p", u); coctx->data = u; - coctx->socket_busy = 1; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -1130,7 +1122,6 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) dd("setting data to %p, coctx:%p", u, coctx); coctx->data = u; - coctx->socket_busy = 1; return lua_yield(L, 0); } @@ -1656,7 +1647,6 @@ ngx_http_lua_socket_tcp_send(lua_State *L) coctx = ctx->cur_co_ctx; coctx->data = u; - coctx->socket_busy = 1; return lua_yield(L, 0); } @@ -2011,7 +2001,6 @@ 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; @@ -2027,9 +2016,6 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - coctx = u->co_ctx; - coctx->socket_busy = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return; @@ -2050,7 +2036,6 @@ 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"); @@ -2067,12 +2052,6 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, if (u->waiting) { u->waiting = 0; - coctx = u->co_ctx; - - dd("setting socket_ready to 1"); - - coctx->socket_busy = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return; @@ -2517,7 +2496,6 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) dd("setting data to %p", u); coctx->data = u; - coctx->socket_busy = 1; return lua_yield(L, 0); } From 357d4d7613a0db11e449bbd378b6b602523e834b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 16:34:32 -0700 Subject: [PATCH 0029/2239] refactor: made the UDP/datagram cosockets schedule their I/O automatically on the Lua coroutine level. --- src/ngx_http_lua_common.h | 4 -- src/ngx_http_lua_socket_udp.c | 94 +++++++++++++++++++++++++---------- src/ngx_http_lua_socket_udp.h | 4 +- src/ngx_http_lua_util.c | 25 ---------- 4 files changed, 71 insertions(+), 56 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 86e27920e1..54944f30ae 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -232,10 +232,6 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ unsigned waiting_flush:1; /* for ngx.flush() */ - - unsigned udp_socket_busy:1; /* for UDP */ - unsigned udp_socket_ready:1; /* for UDP */ - }; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 9d2d873df4..ce0d76821d 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -43,6 +43,7 @@ static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static ngx_int_t ngx_http_lua_udp_connect(ngx_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); +static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); enum { @@ -369,14 +370,12 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) /* still resolving */ + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; coctx = ctx->cur_co_ctx; - coctx->data = u; - coctx->udp_socket_busy = 1; - coctx->udp_socket_ready = 0; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; @@ -392,7 +391,6 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) ngx_http_request_t *r; ngx_http_upstream_resolved_t *ur; ngx_http_lua_ctx_t *lctx; - ngx_http_lua_co_ctx_t *coctx; lua_State *L; ngx_http_lua_socket_udp_upstream_t *u; u_char *p; @@ -507,11 +505,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) u->waiting = 0; if (waiting) { - coctx = lctx->cur_co_ctx; - - coctx->udp_socket_busy = 0; - coctx->udp_socket_ready = 1; - + lctx->resume_handler = ngx_http_lua_socket_udp_resume; r->write_event_handler(r); } else { @@ -888,14 +882,12 @@ ngx_http_lua_socket_udp_receive(lua_State *L) r->write_event_handler = ngx_http_lua_content_wev_handler; } + u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_udp_receive_retval_handler; coctx = ctx->cur_co_ctx; - coctx->data = u; - coctx->udp_socket_busy = 1; - coctx->udp_socket_ready = 0; return lua_yield(L, 0); } @@ -1109,7 +1101,6 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_udp_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 udp socket handle error"); @@ -1126,13 +1117,11 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, u->waiting = 0; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } - dd("setting socket_ready to 1"); - - coctx = ctx->cur_co_ctx; - - coctx->udp_socket_busy = 0; - coctx->udp_socket_ready = 1; + ctx->resume_handler = ngx_http_lua_socket_udp_resume; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); @@ -1190,7 +1179,6 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u) { ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; u->read_event_handler = ngx_http_lua_socket_dummy_handler; @@ -1198,13 +1186,11 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, u->waiting = 0; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } - dd("setting socket_ready to 1"); - - coctx = ctx->cur_co_ctx; - - coctx->udp_socket_busy = 0; - coctx->udp_socket_ready = 1; + ctx->resume_handler = ngx_http_lua_socket_udp_resume; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); @@ -1360,3 +1346,59 @@ ngx_http_lua_socket_udp_close(lua_State *L) return 1; } + +static ngx_int_t +ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) +{ + int nret; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_main_conf_t *lmcf; + + ngx_http_lua_socket_udp_upstream_t *u; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run subrequests done, resuming lua thread"); + + coctx = ctx->cur_co_ctx; + + u = coctx->data; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua udp socket calling prepare retvals handler %p, " + "u:%p", u->prepare_retvals, u); + + nret = u->prepare_retvals(r, u, ctx->cur_co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + diff --git a/src/ngx_http_lua_socket_udp.h b/src/ngx_http_lua_socket_udp.h index 8381496914..b64fcc8c2e 100644 --- a/src/ngx_http_lua_socket_udp.h +++ b/src/ngx_http_lua_socket_udp.h @@ -36,7 +36,9 @@ struct ngx_http_lua_socket_udp_upstream_s { size_t received; /* for receive */ size_t recv_buf_size; - unsigned waiting:1; + ngx_http_lua_co_ctx_t *co_ctx; + + unsigned waiting; /* :1 */ }; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 564174db51..30d3c794db 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1155,8 +1155,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_chain_t *cl; ngx_http_lua_co_ctx_t *coctx; - ngx_http_lua_socket_udp_upstream_t *udp; - c = r->connection; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -1297,29 +1295,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (coctx->udp_socket_busy && !coctx->udp_socket_ready) { - return NGX_DONE; - } - - if (!coctx->udp_socket_busy && coctx->udp_socket_ready) { - coctx->udp_socket_ready = 0; - - udp = coctx->data; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua dup socket calling prepare retvals handler %p", - udp->prepare_retvals); - - nret = udp->prepare_retvals(r, udp, ctx->cur_co); - if (nret == NGX_AGAIN) { - return NGX_DONE; - } - - ngx_http_lua_probe_info("udp cosocket hit"); - - goto run; - } - if (coctx->waiting_flush) { coctx->waiting_flush = 0; From 12981c904402ca13ee6ed3ea2055d2a35423d2b6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 17:22:09 -0700 Subject: [PATCH 0030/2239] refactor: made the ngx.req.socket() objects keep track of the current Lua coroutine themselves. also disabled the ngx.req.socket() API in subrequests to prevent potential problems. --- src/ngx_http_lua_common.h | 4 ++++ src/ngx_http_lua_socket_tcp.c | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 54944f30ae..138a93782e 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -255,6 +255,10 @@ typedef struct ngx_http_lua_ctx_s { ngx_array_t *user_co_ctx; /* coroutine contexts for user coroutines */ + ngx_http_lua_co_ctx_t *req_socket_co_ctx; /* coroutine context for the + coroutine using the + ngx.req.socket() API */ + ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the entry coroutine */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 88a038aa4a..50d14ec973 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -869,8 +869,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, dd("setting data to %p", u); - coctx->data = u; - if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } @@ -1123,6 +1121,10 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) coctx->data = u; + if (u->is_downstream) { + ctx->req_socket_co_ctx = coctx; + } + return lua_yield(L, 0); } @@ -2497,6 +2499,10 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) coctx->data = u; + if (u->is_downstream) { + ctx->req_socket_co_ctx = coctx; + } + return lua_yield(L, 0); } @@ -2833,6 +2839,11 @@ ngx_http_lua_req_socket(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + if (r != r->main) { + return luaL_error(L, "attempt to read the request body in a " + "subrequest"); + } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); @@ -2936,6 +2947,7 @@ ngx_http_lua_req_socket(lua_State *L) dd("setting data to %p", u); coctx->data = u; + ctx->req_socket_co_ctx = coctx; r->read_event_handler = ngx_http_lua_req_socket_rev_handler; @@ -2964,8 +2976,7 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) return; } - coctx = ctx->cur_co_ctx; - + coctx = ctx->req_socket_co_ctx; u = coctx->data; if (u) { From 6fba5e1bff624fd0ccc2dcd599e38d8ae89032a7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 17:32:47 -0700 Subject: [PATCH 0031/2239] refactor: made ngx.req.socket() use the existing req_body_reader_co_ctx field in the context struct. --- src/ngx_http_lua_common.h | 4 ---- src/ngx_http_lua_socket_tcp.c | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 138a93782e..54944f30ae 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -255,10 +255,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_array_t *user_co_ctx; /* coroutine contexts for user coroutines */ - ngx_http_lua_co_ctx_t *req_socket_co_ctx; /* coroutine context for the - coroutine using the - ngx.req.socket() API */ - ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the entry coroutine */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 50d14ec973..ac0bf008ae 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1122,7 +1122,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) coctx->data = u; if (u->is_downstream) { - ctx->req_socket_co_ctx = coctx; + ctx->req_body_reader_co_ctx = coctx; } return lua_yield(L, 0); @@ -2500,7 +2500,7 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) coctx->data = u; if (u->is_downstream) { - ctx->req_socket_co_ctx = coctx; + ctx->req_body_reader_co_ctx = coctx; } return lua_yield(L, 0); @@ -2947,7 +2947,7 @@ ngx_http_lua_req_socket(lua_State *L) dd("setting data to %p", u); coctx->data = u; - ctx->req_socket_co_ctx = coctx; + ctx->req_body_reader_co_ctx = coctx; r->read_event_handler = ngx_http_lua_req_socket_rev_handler; @@ -2976,7 +2976,7 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) return; } - coctx = ctx->req_socket_co_ctx; + coctx = ctx->req_body_reader_co_ctx; u = coctx->data; if (u) { From 9155f9400da86ed15c344a81f37d1426b9bae73a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 17:55:40 -0700 Subject: [PATCH 0032/2239] refactor: made ngx.req.read_body() keep track of the current Lua coroutine automatically. --- src/ngx_http_lua_common.h | 3 -- src/ngx_http_lua_req_body.c | 60 ++++++++++++++++++++++++++++++------- src/ngx_http_lua_util.c | 24 --------------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 54944f30ae..0dbc1b9183 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -296,9 +296,6 @@ typedef struct ngx_http_lua_ctx_s { post_subrequest (for subrequests only) */ - unsigned req_read_body_done:1; /* used by - ngx.req.read_body */ - unsigned waiting_more_body:1; /* 1: waiting for more request body data; 0: no need to wait */ diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 53f503bae6..4c5b2ad42e 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -21,7 +21,8 @@ static int ngx_http_lua_ngx_req_init_body(lua_State *L); static int ngx_http_lua_ngx_req_append_body(lua_State *L); static int ngx_http_lua_ngx_req_body_finish(lua_State *L); static ngx_int_t ngx_http_lua_write_request_body(ngx_http_request_t *r, - ngx_chain_t *body); + ngx_chain_t *body); +static ngx_int_t ngx_http_lua_read_body_resume(ngx_http_request_t *r); void @@ -118,7 +119,6 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) "lua read buffered request body requires I/O interruptions"); ctx->waiting_more_body = 1; - ctx->req_read_body_done = 0; ctx->req_body_reader_co_ctx = coctx; return lua_yield(L, 0); @@ -126,8 +126,6 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) /* rc == NGX_OK */ - ctx->req_read_body_done = 0; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua has read buffered request body in a single run"); @@ -138,13 +136,13 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) static void ngx_http_lua_req_body_post_read(ngx_http_request_t *r) { - ngx_http_lua_ctx_t *ctx; + 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 req body post read"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - ctx->req_read_body_done = 1; #if defined(nginx_version) && nginx_version >= 8011 r->main->count--; @@ -153,10 +151,15 @@ 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; + ctx->cur_co_ctx = coctx; + ctx->cur_co = coctx->co; + if (ctx->entered_content_phase) { - (void) ctx->resume_handler(r); + (void) ngx_http_lua_read_body_resume(r); } else { + ctx->resume_handler = ngx_http_lua_read_body_resume; ngx_http_core_run_phases(r); } } @@ -621,9 +624,10 @@ ngx_http_lua_ngx_req_append_body(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); - if (r->request_body == NULL || r->request_body->buf == NULL - || r->request_body->bufs == NULL) { - + if (r->request_body == NULL + || r->request_body->buf == NULL + || r->request_body->bufs == NULL) + { return luaL_error(L, "request_body not initalized"); } @@ -1070,3 +1074,39 @@ ngx_http_lua_write_request_body(ngx_http_request_t *r, ngx_chain_t *body) return NGX_OK; } + +static ngx_int_t +ngx_http_lua_read_body_resume(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_main_conf_t *lmcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 30d3c794db..6edc058453 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1220,14 +1220,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_OK; } - if (ctx->waiting_more_body && !ctx->req_read_body_done) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua write event handler waiting for more request " - "body data"); - - return NGX_DONE; - } - dd("req read body done: %d", (int) ctx->req_read_body_done); if (c->buffered) { @@ -1305,22 +1297,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) goto run; } - if (ctx->req_read_body_done) { - - dd("turned off req read body done"); - - ctx->req_read_body_done = 0; - - nret = 0; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua read req body done, resuming lua thread"); - - ngx_http_lua_probe_info("req read body hit"); - - goto run; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "useless lua write event handler"); From 59c5231b8c58bcf8e15718a9e6a0fdb31ca4ff56 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 19:34:53 -0700 Subject: [PATCH 0033/2239] refactor: renamed the confusing "waiting" field of ngx_http_lua_co_ctx_t to "pending_subreqs". --- src/ngx_http_lua_common.h | 4 ++-- src/ngx_http_lua_subrequest.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 0dbc1b9183..cac0692ae8 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -226,8 +226,8 @@ struct ngx_http_lua_co_ctx_s { ngx_str_t *sr_bodies; /* all captured subrequest bodies */ - unsigned waiting; /* number of subrequests being - waited */ + unsigned pending_subreqs; /* number of subrequests being + waited */ ngx_event_t sleep; /* used for ngx.sleep */ diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 400d7c6d22..fe416f792d 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -173,12 +173,12 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) coctx->nsubreqs = nsubreqs; - coctx->waiting = 0; + coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { - coctx->waiting++; + coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { @@ -855,9 +855,9 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) } pr_coctx = psr_data->pr_co_ctx; - pr_coctx->waiting--; + pr_coctx->pending_subreqs--; - if (pr_coctx->waiting == 0) { + if (pr_coctx->pending_subreqs == 0) { dd("all subrequests are done"); pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; @@ -1088,10 +1088,10 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, coctx = ctx->cur_co_ctx; for (index = 0; index < coctx->nsubreqs; index++) { - dd("summary: reqs %d, subquery %d, waiting %d, req %.*s", + dd("summary: reqs %d, subquery %d, pending %d, req %.*s", (int) coctx->nsubreqs, (int) index, - (int) coctx->waiting, + (int) coctx->pending_subreqs, (int) r->uri.len, r->uri.data); /* {{{ construct ret value */ From 240caaa72ec8585876e530413649ec8edf4ca785 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 11 Sep 2012 22:38:37 -0700 Subject: [PATCH 0034/2239] refactor: made ngx.flush(true) keep track of the current Lua coroutine automatically. --- src/ngx_http_lua_common.h | 8 ++- src/ngx_http_lua_output.c | 34 +++++++++++- src/ngx_http_lua_output.h | 3 ++ src/ngx_http_lua_sleep.c | 5 +- src/ngx_http_lua_socket_tcp.c | 3 ++ src/ngx_http_lua_socket_udp.c | 3 ++ src/ngx_http_lua_subrequest.c | 5 +- src/ngx_http_lua_util.c | 98 +++++++++++++++++++---------------- 8 files changed, 107 insertions(+), 52 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index cac0692ae8..91837ed9dd 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -231,7 +231,9 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ - unsigned waiting_flush:1; /* for ngx.flush() */ + unsigned flushing; /* :1 indicates whether the current + coroutine is waiting for + ngx.flush(true) */ }; @@ -248,7 +250,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ - lua_State *entry_co; /* the entry Lua coroutine */ /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ @@ -268,6 +269,9 @@ typedef struct ngx_http_lua_ctx_s { request ctx data in lua registry */ + unsigned flushing_coros; /* number of coroutines waiting on + ngx.flush(true) */ + ngx_chain_t *out; /* buffered output chain for HTTP 1.0 */ ngx_chain_t *free_bufs; ngx_chain_t *busy_bufs; diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index fe1c632914..d0212f9042 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -543,7 +543,8 @@ ngx_http_lua_ngx_flush(lua_State *L) "lua flush requires waiting: buffered 0x%uxd", (int) r->connection->buffered); - coctx->waiting_flush = 1; + coctx->flushing = 1; + ctx->flushing_coros++; if (ctx->entered_content_phase) { /* mimic ngx_http_set_write_handler */ @@ -678,3 +679,34 @@ ngx_http_lua_ngx_send_headers(lua_State *L) return 0; } + +ngx_int_t +ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_http_lua_main_conf_t *lmcf; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return NGX_DONE; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + diff --git a/src/ngx_http_lua_output.h b/src/ngx_http_lua_output.h index 4596bb0218..72d3845524 100644 --- a/src/ngx_http_lua_output.h +++ b/src/ngx_http_lua_output.h @@ -12,6 +12,9 @@ size_t ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, u_char * ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst); +ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx); + #endif /* NGX_HTTP_LUA_OUTPUT_H */ diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 2969493edd..ae9f0b47f9 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -173,6 +173,9 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) ngx_http_lua_main_conf_t *lmcf; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } ctx->resume_handler = ngx_http_lua_wev_handler; @@ -197,8 +200,6 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) return NGX_DONE; } - r->write_event_handler = ngx_http_core_run_phases; - return rc; } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index ac0bf008ae..478a0311e2 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3828,6 +3828,9 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) ngx_http_lua_socket_tcp_upstream_t *u; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } ctx->resume_handler = ngx_http_lua_wev_handler; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index ce0d76821d..5adecf737c 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1359,6 +1359,9 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) ngx_http_lua_socket_udp_upstream_t *u; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } ctx->resume_handler = ngx_http_lua_wev_handler; diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index fe416f792d..d81bb72848 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1421,6 +1421,9 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) ngx_http_lua_main_conf_t *lmcf; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } ctx->resume_handler = ngx_http_lua_wev_handler; @@ -1464,8 +1467,6 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) return NGX_DONE; } - r->write_event_handler = ngx_http_core_run_phases; - return rc; } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 6edc058453..6940fe9cdb 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1147,13 +1147,12 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_lua_ctx_t *ctx; - ngx_http_lua_main_conf_t *lmcf; - int nret = 0; 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; c = r->connection; @@ -1164,11 +1163,9 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - goto error; + return NGX_ERROR; } - coctx = ctx->cur_co_ctx; - clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); if (wev->timedout) { @@ -1270,7 +1267,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_ERROR; } - if (coctx->waiting_flush) { + if (ctx->flushing_coros) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua flush still waiting: buffered 0x%uxd", c->buffered); @@ -1287,66 +1284,77 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - if (coctx->waiting_flush) { + if (ctx->flushing_coros) { - coctx->waiting_flush = 0; - nret = 0; + coctx = &ctx->entry_co_ctx; - ngx_http_lua_probe_info("waiting flush hit"); + if (coctx->flushing) { + coctx->flushing = 0; - goto run; - } + ctx->flushing_coros--; + ctx->cur_co_ctx = coctx; + ctx->cur_co = coctx->co; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "useless lua write event handler"); + rc = ngx_http_lua_flush_resume_helper(r, ctx); + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } -#if 0 - if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, NGX_DONE); - } -#endif + /* rc == NGX_DONE */ + } - if (ctx->entered_content_phase) { - return NGX_OK; - } + if (ctx->flushing_coros) { - return NGX_DONE; + if (ctx->user_co_ctx == NULL) { + return NGX_ERROR; + } -run: - lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + coctx = ctx->user_co_ctx->elts; + + i = 0; + do { + for ( ;; ) { + if (i >= ctx->user_co_ctx->nelts) { + return NGX_ERROR; + } - dd("about to run thread for %.*s...", (int) r->uri.len, r->uri.data); + if (coctx[i].flushing) { + coctx[i].flushing = 0; + ctx->cur_co_ctx = &coctx[i]; + ctx->cur_co = coctx[i].co; + break; + } - rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); + i++; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua run thread returned %d", rc); + rc = ngx_http_lua_flush_resume_helper(r, ctx); + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } - if (rc == NGX_AGAIN) { - return NGX_DONE; - } + /* rc == NGX_DONE */ - if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; - } + } while (--ctx->flushing_coros); + } - dd("entered content phase: %d", (int) ctx->entered_content_phase); + if (ctx->flushing_coros) { + return NGX_ERROR; + } - if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, rc); return NGX_DONE; } - return rc; + /* ctx->flushing_coros == 0 */ -error: - if (ctx && ctx->entered_content_phase) { - ngx_http_finalize_request(r, - ctx->headers_sent ? NGX_ERROR: NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "useless lua write event handler"); + + if (ctx->entered_content_phase) { + return NGX_OK; } - return NGX_ERROR; + return NGX_DONE; } From 644b0b15c9cddeefdaf3a7bf066d3dabf23a778e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 12:04:32 -0700 Subject: [PATCH 0035/2239] cleaned up the code a bit in ngx_http_lua_wev_handler. --- src/ngx_http_lua_util.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 6940fe9cdb..451738e370 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1194,17 +1194,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } - dd("wev handler %.*s %.*s a:%d, postponed:%p", - (int) r->uri.len, r->uri.data, - (int) ngx_cached_err_log_time.len, - ngx_cached_err_log_time.data, - r == c->data, - r->postponed); - - dd("ctx = %p", ctx); - dd("request done: %d", (int) r->done); - dd("cleanup done: %p", ctx->cleanup); - +#if 0 if (ctx->cleanup == NULL) { /* already done */ dd("cleanup is null: %.*s", (int) r->uri.len, r->uri.data); @@ -1216,8 +1206,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_OK; } - - dd("req read body done: %d", (int) ctx->req_read_body_done); +#endif if (c->buffered) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, From 2fbb4ada9920983df5b19d68ffeaf27762043638 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 14:43:45 -0700 Subject: [PATCH 0036/2239] refactor: removed the "cur_co" field from ngx_http_lua_ctx_t because it is not necessary at all. --- src/ngx_http_lua_accessby.c | 1 - src/ngx_http_lua_common.h | 4 ---- src/ngx_http_lua_contentby.c | 1 - src/ngx_http_lua_coroutine.c | 1 - src/ngx_http_lua_req_body.c | 1 - src/ngx_http_lua_rewriteby.c | 1 - src/ngx_http_lua_sleep.c | 1 - src/ngx_http_lua_socket_tcp.c | 4 ++-- src/ngx_http_lua_socket_udp.c | 4 ++-- src/ngx_http_lua_subrequest.c | 3 +-- src/ngx_http_lua_util.c | 42 ++++++++++++++++------------------- 11 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 88d1543279..e6989c5268 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -255,7 +255,6 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entered_access_phase = 1; ctx->entry_co = co; - ctx->cur_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 91837ed9dd..1875a90054 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -244,10 +244,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_handler_pt resume_handler; - lua_State *cur_co; /* the current running Lua coroutine, - not necessarily to be the - request's entry coroutine */ - ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ lua_State *entry_co; /* the entry Lua coroutine */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 1f7f162649..9b9f533f7b 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -64,7 +64,6 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) /* }}} */ ctx->entry_co = co; - ctx->cur_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 6a0815a43c..1655cbf868 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -152,7 +152,6 @@ ngx_http_lua_coroutine_resume(lua_State *L) ctx->co_op = NGX_HTTP_LUA_USER_CORO_RESUME; ctx->cur_co_ctx = coctx; - ctx->cur_co = co; /* yield and pass args to main thread, and resume target coroutine from * there */ diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 4c5b2ad42e..98d3873582 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -153,7 +153,6 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) coctx = ctx->req_body_reader_co_ctx; ctx->cur_co_ctx = coctx; - ctx->cur_co = coctx->co; if (ctx->entered_content_phase) { (void) ngx_http_lua_read_body_resume(r); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 78c09df403..997ba7bcab 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -258,7 +258,6 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entered_rewrite_phase = 1; ctx->entry_co = co; - ctx->cur_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index ae9f0b47f9..401f8270ac 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -125,7 +125,6 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) } ctx->cur_co_ctx = coctx; - ctx->cur_co = coctx->co; if (ctx->entered_content_phase) { (void) ngx_http_lua_sleep_resume(r); diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 478a0311e2..35a13be46f 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -603,7 +603,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) dd("ctx->cur_co_ctx = %p", lctx->cur_co_ctx); dd("u->co_ctx = %p", u->co_ctx); - L = lctx->cur_co; + L = lctx->cur_co_ctx->co; waiting = u->waiting; @@ -3847,7 +3847,7 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) "lua tcp socket calling prepare retvals handler %p, " "u:%p", u->prepare_retvals, u); - nret = u->prepare_retvals(r, u, ctx->cur_co); + nret = u->prepare_retvals(r, u, ctx->cur_co_ctx->co); if (nret == NGX_AGAIN) { return NGX_DONE; } diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 5adecf737c..c37ea90794 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -408,7 +408,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - L = lctx->cur_co; + L = lctx->cur_co_ctx->co; dd("setting socket_ready to 1"); @@ -1378,7 +1378,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) "lua udp socket calling prepare retvals handler %p, " "u:%p", u->prepare_retvals, u); - nret = u->prepare_retvals(r, u, ctx->cur_co); + nret = u->prepare_retvals(r, u, ctx->cur_co_ctx->co); if (nret == NGX_AGAIN) { return NGX_DONE; } diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index d81bb72848..17438fa254 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -862,7 +862,6 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; pr_ctx->cur_co_ctx = pr_coctx; - pr_ctx->cur_co = pr_coctx->co; } if (pr_ctx->entered_content_phase) { @@ -1084,8 +1083,8 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua handle subrequest responses"); - co = ctx->cur_co; coctx = ctx->cur_co_ctx; + co = coctx->co; for (index = 0; index < coctx->nsubreqs; index++) { dd("summary: reqs %d, subquery %d, pending %d, req %.*s", diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 451738e370..5adce5036a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -835,7 +835,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, for ( ;; ) { - dd("calling lua_resume: vm %p, nret %d", ctx->cur_co, (int) nret); + dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, (int) nret); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -845,9 +845,9 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* run code */ dd("ctx: %p", ctx); - dd("cur co: %p", ctx->cur_co); + dd("cur co: %p", ctx->cur_co_ctx->co); - rv = lua_resume(ctx->cur_co, nrets); + rv = lua_resume(ctx->cur_co_ctx->co, nrets); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -894,7 +894,7 @@ 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, 0); + lua_settop(ctx->cur_co_ctx->co, 0); return NGX_AGAIN; case NGX_HTTP_LUA_USER_CORO_RESUME: @@ -911,7 +911,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, nrets = lua_gettop(old_co); if (nrets) { - lua_xmove(old_co, ctx->cur_co, nrets); + lua_xmove(old_co, ctx->cur_co_ctx->co, nrets); } break; @@ -923,21 +923,21 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua coroutine: yield"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - if (ctx->cur_co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co) { /* entry coroutine yielded will be resumed * immediately */ ngx_http_lua_probe_entry_coroutine_yield(r, - ctx->cur_co); + ctx->cur_co_ctx->co); - lua_settop(ctx->cur_co, 0); + lua_settop(ctx->cur_co_ctx->co, 0); nrets = 0; continue; } /* being a user coroutine that has a parent */ - nrets = lua_gettop(ctx->cur_co); + nrets = lua_gettop(ctx->cur_co_ctx->co); next_coctx = ctx->cur_co_ctx->parent_co_ctx; next_co = next_coctx->co; @@ -949,13 +949,12 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_pushboolean(next_co, 1); if (nrets) { - lua_xmove(ctx->cur_co, next_co, nrets); + lua_xmove(ctx->cur_co_ctx->co, next_co, nrets); } nrets++; ctx->cur_co_ctx = next_coctx; - ctx->cur_co = next_co; break; } @@ -967,7 +966,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - if (ctx->cur_co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co) { dd("hit! it is the entry"); lua_settop(L, 0); /* discard return values */ @@ -995,7 +994,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* being a user coroutine that has a parent */ - nrets = lua_gettop(ctx->cur_co); + nrets = lua_gettop(ctx->cur_co_ctx->co); next_coctx = ctx->cur_co_ctx->parent_co_ctx; @@ -1013,11 +1012,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_pushboolean(next_co, 1); if (nrets) { - lua_xmove(ctx->cur_co, next_co, nrets); + lua_xmove(ctx->cur_co_ctx->co, next_co, nrets); } nrets++; - ctx->cur_co = next_co; ctx->cur_co_ctx = next_coctx; dd("set coroutine to running"); @@ -1054,19 +1052,19 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, break; } - if (lua_isstring(ctx->cur_co, -1)) { + if (lua_isstring(ctx->cur_co_ctx->co, -1)) { dd("user custom error msg"); - msg = lua_tostring(ctx->cur_co, -1); + msg = lua_tostring(ctx->cur_co_ctx->co, -1); } else { msg = "unknown reason"; } - ngx_http_lua_thread_traceback(L, ctx->cur_co, ctx->cur_co_ctx); + ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co, ctx->cur_co_ctx); trace = lua_tostring(L, -1); lua_pop(L, 1); - if (ctx->cur_co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: %s: %s\n%s", err, msg, trace); @@ -1100,10 +1098,9 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, * err msg */ lua_pushboolean(next_co, 0); - lua_xmove(ctx->cur_co, next_co, 1); + lua_xmove(ctx->cur_co_ctx->co, next_co, 1); nrets = 2; - ctx->cur_co = next_co; ctx->cur_co_ctx = next_coctx; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -1282,7 +1279,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ctx->flushing_coros--; ctx->cur_co_ctx = coctx; - ctx->cur_co = coctx->co; + ctx->cur_co_ctx->co = coctx->co; rc = ngx_http_lua_flush_resume_helper(r, ctx); if (rc == NGX_ERROR || rc >= NGX_OK) { @@ -1310,7 +1307,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (coctx[i].flushing) { coctx[i].flushing = 0; ctx->cur_co_ctx = &coctx[i]; - ctx->cur_co = coctx[i].co; break; } From 79dee2697a091726645afb2eaa0df700ae01cbdd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 14:45:39 -0700 Subject: [PATCH 0037/2239] coding style fixes and also fixed a warning in clang. --- src/ngx_http_lua_util.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 5adce5036a..0176336e1c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -835,7 +835,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, for ( ;; ) { - dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, (int) nret); + dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, + (int) nret); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ @@ -928,7 +929,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, * immediately */ ngx_http_lua_probe_entry_coroutine_yield(r, - ctx->cur_co_ctx->co); + ctx->cur_co_ctx->co); lua_settop(ctx->cur_co_ctx->co, 0); nrets = 0; @@ -1060,7 +1061,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, msg = "unknown reason"; } - ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co, ctx->cur_co_ctx); + ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co, + ctx->cur_co_ctx); trace = lua_tostring(L, -1); lua_pop(L, 1); @@ -1279,7 +1281,6 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ctx->flushing_coros--; ctx->cur_co_ctx = coctx; - ctx->cur_co_ctx->co = coctx->co; rc = ngx_http_lua_flush_resume_helper(r, ctx); if (rc == NGX_ERROR || rc >= NGX_OK) { From fe8d7be13249f84d8ed5a84f6c62cc04d574733e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 15:08:05 -0700 Subject: [PATCH 0038/2239] optimize: we now skip processing in the default write event handler when the write event is not ready. --- src/ngx_http_lua_util.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0176336e1c..4c782adc13 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1193,19 +1193,9 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) } } -#if 0 - if (ctx->cleanup == NULL) { - /* already done */ - dd("cleanup is null: %.*s", (int) r->uri.len, r->uri.data); - - if (ctx->entered_content_phase) { - ngx_http_finalize_request(r, - ngx_http_lua_flush_postponed_outputs(r)); - } - - return NGX_OK; + if (!wev->ready) { + goto useless; } -#endif if (c->buffered) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -1333,6 +1323,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) /* ctx->flushing_coros == 0 */ +useless: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "useless lua write event handler"); From e49622d8b6e4ab9925b76bd12bef6fbf88089322 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 15:21:27 -0700 Subject: [PATCH 0039/2239] added a (passing) test case for using ngx.flush(true) in a user coroutine. --- t/056-flush.t | 100 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/t/056-flush.t b/t/056-flush.t index e6af50236f..8577056767 100644 --- a/t/056-flush.t +++ b/t/056-flush.t @@ -14,10 +14,10 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * 41; +plan tests => repeat_each() * 44; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -294,3 +294,99 @@ lua buffering output bufs for the HTTP 1.0 request lua http 1.0 buffering makes ngx.flush() a no-op --- timeout: 5 + + +=== TEST 13: flush wait in a user coroutine +--- config + location /test { + content_by_lua ' + function f() + ngx.say("hello, world") + ngx.flush(true) + coroutine.yield() + ngx.say("hiya") + end + local c = coroutine.create(f) + ngx.say(coroutine.resume(c)) + ngx.say(coroutine.resume(c)) + '; + } +--- request +GET /test +--- stap2 +F(ngx_http_lua_wev_handler) { + printf("wev handler: wev:%d\n", $r->connection->write->ready) +} + +global ids, cur + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_handler) { + delete ids + cur = 0 +} + +/* +F(ngx_http_lua_run_thread) { + id = gen_id($ctx->cur_co) + printf("run thread %d\n", id) +} + +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { + id = gen_id($L) + printf("lua resume %d\n", id) +} +*/ + +M(http-lua-user-coroutine-resume) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("resume %x in %x\n", c, p) +} + +M(http-lua-entry-coroutine-yield) { + println("entry coroutine yield") +} + +/* +F(ngx_http_lua_coroutine_yield) { + printf("yield %x\n", gen_id($L)) +} +*/ + +M(http-lua-user-coroutine-yield) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("yield %x in %x\n", c, p) +} + +F(ngx_http_lua_atpanic) { + printf("lua atpanic(%d):", gen_id($L)) + print_ubacktrace(); +} + +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + +F(ngx_http_lua_ngx_exec) { println("exec") } + +F(ngx_http_lua_ngx_exit) { println("exit") } + +F(ngx_http_writer) { println("http writer") } + +--- response_body +hello, world +true +hiya +true +--- error_log +lua reuse free buf memory 13 >= 5 + From e0adfe5ec4b6af4903b16f70daf10016fc1c5fe9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 17:06:14 -0700 Subject: [PATCH 0040/2239] bugfix: the UDP and TCP cosockets could not keep track of the current Lua coroutine. now we also explicitly clear the current Lua coroutine context in the main request context to ensure that the I/O scheduler can indeed keep track of the current Lua coroutine itself. --- src/ngx_http_lua_socket_tcp.c | 20 ++++-- src/ngx_http_lua_socket_udp.c | 15 ++++- src/ngx_http_lua_util.c | 2 + t/058-tcp-socket.t | 13 ++++ t/087-udp-socket.t | 118 +++++++++++++++++++++++++++++++++- 5 files changed, 158 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 35a13be46f..f59acec362 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -528,6 +528,9 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) rctx->timeout = clcf->resolver_timeout; u->resolved->ctx = rctx; + u->co_ctx = ctx->cur_co_ctx; + + coctx->data = u; saved_top = lua_gettop(L); @@ -558,14 +561,11 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) /* still resolving */ - u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; dd("setting data to %p", u); - coctx->data = u; - if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } @@ -600,9 +600,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) return; } - dd("ctx->cur_co_ctx = %p", lctx->cur_co_ctx); - dd("u->co_ctx = %p", u->co_ctx); - + lctx->cur_co_ctx = u->co_ctx; L = lctx->cur_co_ctx->co; waiting = u->waiting; @@ -2024,6 +2022,7 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -2060,6 +2059,7 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_tcp_resume; + ctx->cur_co_ctx = u->co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket waking up the current request"); @@ -3837,10 +3837,16 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run subrequests done, resuming lua thread"); + "lua tcp operation done, resuming lua thread"); coctx = ctx->cur_co_ctx; +#if 0 + ngx_http_lua_probe_info("tcp resume"); +#endif + + dd("coctx: %p", coctx); + u = coctx->data; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index c37ea90794..e31ea153ee 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -9,6 +9,7 @@ #include "ngx_http_lua_util.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_output.h" +#include "ngx_http_lua_probe.h" #define UDP_MAX_DATAGRAM_SIZE 8192 @@ -339,6 +340,7 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) rctx->data = u; rctx->timeout = clcf->resolver_timeout; + u->co_ctx = ctx->cur_co_ctx; u->resolved->ctx = rctx; saved_top = lua_gettop(L); @@ -370,7 +372,6 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) /* still resolving */ - u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; @@ -407,7 +408,11 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) "lua udp socket resolve handler"); lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (lctx == NULL) { + return; + } + lctx->cur_co_ctx = u->co_ctx; L = lctx->cur_co_ctx->co; dd("setting socket_ready to 1"); @@ -1122,6 +1127,7 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_udp_resume; + ctx->cur_co_ctx = u->co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); @@ -1191,6 +1197,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, } ctx->resume_handler = ngx_http_lua_socket_udp_resume; + ctx->cur_co_ctx = u->co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket waking up the current request"); @@ -1368,10 +1375,14 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run subrequests done, resuming lua thread"); + "lua udp operation done, resuming lua thread"); coctx = ctx->cur_co_ctx; +#if 0 + ngx_http_lua_probe_info("udp resume"); +#endif + u = coctx->data; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 4c782adc13..e38b086f74 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -896,6 +896,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, dd("hit! it is the API yield"); lua_settop(ctx->cur_co_ctx->co, 0); + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; case NGX_HTTP_LUA_USER_CORO_RESUME: diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 82f314f362..163e7ea906 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -967,6 +967,13 @@ close: nil closed } --- request GET /test + +--- stap2 +M(http-lua-info) { + printf("tcp resume: %p\n", $coctx) + print_ubacktrace() +} + --- response_body failed to connect: connection refused --- error_log @@ -1167,6 +1174,12 @@ function go(port) ngx.say("failed to receive a line: ", err, " [", part, "]") end end + +--- stap2 +M(http-lua-info) { + printf("tcp resume\n") + print_ubacktrace() +} --- request GET /t --- response_body_like eval diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 459af50e41..be8af2800c 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() + 4); +plan tests => repeat_each() * (3 * blocks() + 6); our $HtmlDir = html_dir; @@ -252,6 +252,13 @@ function get_udp() return udp end + +--- stap2 +M(http-lua-info) { + printf("tcp resume: %p\n", $coctx) + print_ubacktrace() +} + --- request GET /main --- response_body_like: \b500\b @@ -537,3 +544,112 @@ received: hello world --- error_log lua udp socket read timed out + + +=== TEST 10: access the google DNS server (using IP addr) +--- config + server_tokens off; + location /t { + content_by_lua ' + local socket = ngx.socket + -- local socket = require "socket" + + local udp = socket.udp() + + udp:settimeout(2000) -- 2 sec + + local ok, err = udp:setpeername("8.8.8.8", 53) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "\\0}\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\6google\\3com\\0\\0\\1\\0\\1" + + -- ngx.print(req) + -- do return end + + local ok, err = udp:send(req) + if not ok then + ngx.say("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + ngx.say("failed to receive data: ", err) + return + end + + if string.match(data, "\\3www\\6google\\3com") then + ngx.say("received a good response.") + else + ngx.say("received a bad response: ", #data, " bytes: ", data) + end + '; + } +--- request +GET /t +--- response_body +received a good response. +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua udp socket receive buffer size: 8192 + + + +=== TEST 11: access the google DNS server (using domain names) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER; + location /t { + content_by_lua ' + local socket = ngx.socket + -- local socket = require "socket" + + local udp = socket.udp() + + udp:settimeout(2000) -- 2 sec + + local ok, err = udp:setpeername("google-public-dns-a.google.com", 53) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "\\0}\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\3www\\6google\\3com\\0\\0\\1\\0\\1" + + -- ngx.print(req) + -- do return end + + local ok, err = udp:send(req) + if not ok then + ngx.say("failed to send: ", err) + return + end + + local data, err = udp:receive() + if not data then + ngx.say("failed to receive data: ", err) + return + end + + if string.match(data, "\\3www\\6google\\3com") then + ngx.say("received a good response.") + else + ngx.say("received a bad response: ", #data, " bytes: ", data) + end + '; + } +--- request +GET /t +--- response_body +received a good response. +--- no_error_log +[error] +--- log_level: debug +--- error_log +lua udp socket receive buffer size: 8192 + From b1289817d905b66d3579f8f5f8555a3024fffe61 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 12 Sep 2012 20:45:53 -0700 Subject: [PATCH 0041/2239] added (passing) tests for using parallel subrequests after ngx.eof(). --- t/092-eof.t | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 t/092-eof.t diff --git a/t/092-eof.t b/t/092-eof.t new file mode 100644 index 0000000000..f05fd63f16 --- /dev/null +++ b/t/092-eof.t @@ -0,0 +1,84 @@ +# 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() * 6); + +master_on(); +workers(2); +no_root_location(); +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: 404 parallel subrequests after ngx.eof() +--- config + location = /lua { + content_by_lua ' + ngx.say(1) + ngx.eof() + local res1, res2 = ngx.location.capture_multi{ + { "/bad1" }, + { "/bad2" } + } + ngx.log(ngx.WARN, "res1: ", res1.status) + ngx.log(ngx.WARN, "res2: ", res2.status) + '; + } +--- request +GET /lua +--- response_body +1 +--- no_error_log +[alert] +--- error_log +res1: 404 +res2: 404 +No such file or directory + + + +=== TEST 2: parallel normal subrequests after ngx.eof() +--- config + location = /t { + content_by_lua ' + ngx.say(1) + ngx.eof() + local r1, r2 = ngx.location.capture_multi{ + { "/proxy/tom" }, + { "/proxy/jim" } + } + ngx.log(ngx.WARN, r1.body) + ngx.log(ngx.WARN, r2.body) + '; + } + + location ~ '^/proxy/(\w+)' { + proxy_pass http://127.0.0.1:$server_port/hello?a=$1; + } + + location = /hello { + echo_sleep 0.5; + echo -n "hello, $arg_a"; + } +--- request +GET /t +--- response_body +1 +--- no_error_log +[alert] +[error] +--- error_log +hello, tom +hello, jim + From 62a0b6960963547a529bf73bf807fe29bfaafa06 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 13 Sep 2012 11:46:55 -0700 Subject: [PATCH 0042/2239] updated docs to reflect recent changes. --- README | 67 ++++++++++++++++++++++++++++++------------ README.markdown | 31 ++++++++++++++----- doc/HttpLuaModule.wiki | 31 ++++++++++++++----- 3 files changed, 96 insertions(+), 33 deletions(-) diff --git a/README b/README index 56562e5e7e..1514d37f54 100644 --- a/README +++ b/README @@ -180,27 +180,57 @@ Synopsis } Description - This module embeds Lua, via the standard Lua interpreter or LuaJIT, 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 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 mod_magnet (), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the 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. (See - ngx.location.capture, ngx.location.capture_multi, ngx.socket.tcp, - [[HttpDrizzleModule]], ngx_postgres - (), [[HttpMemcModule]], - [[HttpRedis2Module]] and [[HttpProxyModule]] modules for details). + 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: + + * lua-resty-memcached + () + + * lua-resty-mysql () + + * lua-resty-redis () + + * lua-resty-dns () + + * lua-resty-upload () + + * ngx_memc + + * ngx_postgres () + + * ngx_redis2 + + * ngx_redis + + * ngx_proxy + + * ngx_fastcgi + + Almost all the Nginx modules can be used with this ngx_lua module by + means of ngx.location.capture or 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. 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. Loaded Lua modules persist in the - nginx worker process level resulting in a small memory footprint even - when under heavy loads. + using lightweight Lua coroutines. + + Loaded Lua modules persist in the nginx worker process level resulting + in a small memory footprint in Lua even when under heavy loads. Directives lua_code_cache @@ -4776,21 +4806,20 @@ Data Sharing within an Nginx Worker processes under an Nginx master, data sharing cannot cross the process boundary between these workers. - If server wide data sharing is required: + If server-wide data sharing is required, then use one or more of the + following approaches: 1. Use the ngx.shared.DICT API provided by this module. - 2. Use only a single nginx worker and a single server. This is however + 2. 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. + single machine). 3. Use data storage mechanisms such as "memcached", "redis", "MySQL" or "PostgreSQL". The ngx_openresty bundle () associated with this module comes with a set of companion Nginx - modules that provide interfaces with these data storage mechanisms. - See the [[HttpMemcModule]], [[HttpRedis2Module]], - [[HttpDrizzleModule]] and HttpPostgresModule - () modules for details + modules and Lua libraries that provide interfaces with these data + storage mechanisms. Known Issues TCP socket connect operation issues diff --git a/README.markdown b/README.markdown index 2a7ab32d51..92ac5b2d70 100644 --- a/README.markdown +++ b/README.markdown @@ -193,13 +193,30 @@ Synopsis Description =========== -This module embeds Lua, via the standard Lua interpreter or LuaJIT, 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 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. (See [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.socket.tcp](http://wiki.nginx.org/HttpLuaModule#ngx.socket.tcp), [HttpDrizzleModule](http://wiki.nginx.org/HttpDrizzleModule), [ngx_postgres](http://github.com/FRiCKLE/ngx_postgres/), [HttpMemcModule](http://wiki.nginx.org/HttpMemcModule), [HttpRedis2Module](http://wiki.nginx.org/HttpRedis2Module) and [HttpProxyModule](http://wiki.nginx.org/HttpProxyModule) modules for details). +requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. -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. -Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint even when under heavy loads. +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) +* [ngx_memc](http://wiki.nginx.org/HttpMemcModule) +* [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) +* [ngx_redis2](http://wiki.nginx.org/HttpRedis2Module) +* [ngx_redis](http://wiki.nginx.org/HttpRedisModule) +* [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. + +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. + +Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. Directives ========== @@ -4287,10 +4304,10 @@ This data sharing technique is essential for high performance Lua applications b 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. -If server wide data sharing is required: +If server-wide data sharing is required, then use one or more of the following approaches: 1. Use the [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT) 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 that provide interfaces with these data storage mechanisms. See the [HttpMemcModule](http://wiki.nginx.org/HttpMemcModule), [HttpRedis2Module](http://wiki.nginx.org/HttpRedis2Module), [HttpDrizzleModule](http://wiki.nginx.org/HttpDrizzleModule) and [HttpPostgresModule](http://github.com/FRiCKLE/ngx_postgres/) modules for details +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. Known Issues ============ diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index b7fc814cea..7f9ae53bc3 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -183,13 +183,30 @@ This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module = Description = -This module embeds Lua, via the standard Lua interpreter or LuaJIT, 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 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. (See [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.socket.tcp|ngx.socket.tcp]], [[HttpDrizzleModule]], [http://github.com/FRiCKLE/ngx_postgres/ ngx_postgres], [[HttpMemcModule]], [[HttpRedis2Module]] and [[HttpProxyModule]] modules for details). +requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. -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. -Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint even when under heavy loads. +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] +* [[HttpMemcModule|ngx_memc]] +* [https://github.com/FRiCKLE/ngx_postgres ngx_postgres] +* [[HttpRedis2Module|ngx_redis2]] +* [[HttpRedisModule|ngx_redis]] +* [[HttpProxyModule|ngx_proxy]] +* [[HttpFastcgiModule|ngx_fastcgi]] + +Almost all the Nginx modules can be used with this ngx_lua module by means of [[#ngx.location.capture|ngx.location.capture]] or [[#ngx.location.capture_multi|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. + +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. + +Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. = Directives = @@ -4136,10 +4153,10 @@ This data sharing technique is essential for high performance Lua applications b 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. -If server wide data sharing is required: +If server-wide data sharing is required, then use one or more of the following approaches: # Use the [[#ngx.shared.DICT|ngx.shared.DICT]] API provided by this module. -# 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. -# Use data storage mechanisms such as memcached, redis, MySQL or PostgreSQL. [http://openresty.org The ngx_openresty bundle] associated with this module comes with a set of companion Nginx modules that provide interfaces with these data storage mechanisms. See the [[HttpMemcModule]], [[HttpRedis2Module]], [[HttpDrizzleModule]] and [http://github.com/FRiCKLE/ngx_postgres/ HttpPostgresModule] modules for details +# 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). +# Use data storage mechanisms such as memcached, redis, MySQL or PostgreSQL. [http://openresty.org The ngx_openresty bundle] associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. = Known Issues = From 5b5a02dbedd69fcf467fd1396fb7c19481fd1179 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 13 Sep 2012 15:21:49 -0700 Subject: [PATCH 0043/2239] fixed a test case in 068-socket-keepalive.t by properly flushing the redis store first. --- t/068-socket-keepalive.t | 19 ++++++++++++++++++- util/build2.sh | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index 24154c7c69..fae624c4a1 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -1346,7 +1346,24 @@ bad argument #3 to 'connect' (bad "pool" option type: boolean) -=== TEST 22: bug in send(): clear the chain writer ctx +=== TEST 22: clear the redis store +--- config + location /t { + redis2_query flushall; + redis2_pass 127.0.0.1:$TEST_NGINX_REDIS_PORT; + } +--- request + GET /t +--- response_body eval +"+OK\r\n" +--- no_error_log +[error] +[alert] +[warn] + + + +=== TEST 23: bug in send(): clear the chain writer ctx --- http_config eval "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config diff --git a/util/build2.sh b/util/build2.sh index daa315a31c..13a5fa8fa5 100755 --- a/util/build2.sh +++ b/util/build2.sh @@ -43,6 +43,7 @@ time ngx-build $force $version \ --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 \ --with-select_module \ --with-poll_module \ --with-rtsig_module \ From 0c14852af3556ed8d26ba924453db2dae338a325 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 14 Sep 2012 14:51:08 -0700 Subject: [PATCH 0044/2239] suppressed the warnings reported by valgrind 3.8.0. --- valgrind.suppress | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/valgrind.suppress b/valgrind.suppress index eef8401b96..d436c38d9e 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,5 +1,20 @@ { +Memcheck:Param +sendmsg(msg.msg_iov[0]) +fun:__sendmsg_nocancel +fun:ngx_write_channel +fun:ngx_pass_open_channel +} +{ + +Memcheck:Param +sendmsg(msg.msg_iov[0]) +fun:__sendmsg_nocancel +fun:ngx_write_channel +} +{ + Memcheck:Leak fun:malloc fun:ngx_alloc From 66e2d98b052cd638fb2c98c4b31f8d4fbe21f9e9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 15 Sep 2012 13:16:22 -0700 Subject: [PATCH 0045/2239] docs: bumped version number to 0.6.5 and also documented the trick for doing background async jobs by using ngx.eof() + keepalive_timeout 0. --- README | 33 ++++++++++++++++++++++++++++++--- README.markdown | 23 +++++++++++++++++++++-- doc/HttpLuaModule.wiki | 23 +++++++++++++++++++++-- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/README b/README index 1514d37f54..03141ded7c 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.6.4 - () released on 9 + This document describes ngx_lua v0.6.5 + () released on 15 September 2012. Synopsis @@ -3018,7 +3018,34 @@ Nginx API for Lua context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - Explicitly specify the end of the response output stream. + Explicitly specify the end of the response output stream. In the case of + HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to + send out the "last chunk". + + When you disable the HTTP 1.1 keep-alive feature for your downstream + connections, you can rely on descent HTTP clients to close the + connection actively for you when you call this method. This trick can be + used do back-ground jobs without letting the HTTP clients to wait on the + connection, as in the following example: + + location = /async { + keepalive_timeout 0; + content_by_lua ' + ngx.say("got the task!") + ngx.eof() -- descent HTTP client will close the connection at this point + -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... + '; + } + + But if you create subrequests to access other locations configured by + Nginx upstream modules, then you should configure those upstream modules + to ignore client connection abortions if they are not by default. For + example, by default the standard [[HttpProxyModule]] will terminate both + the subrequest and the main request as soon as the client closes the + connection, so it is important to turn on the proxy_ignore_client_abort + directive in your location block configured by [[HttpProxyModule]]: + + proxy_ignore_client_abort on; ngx.sleep syntax: *ngx.sleep(seconds)* diff --git a/README.markdown b/README.markdown index 92ac5b2d70..b090d0e5cc 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.6.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 September 2012. +This document describes ngx_lua [v0.6.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 15 September 2012. Synopsis ======== @@ -2786,7 +2786,26 @@ ngx.eof **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Explicitly specify the end of the response output stream. +Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". + +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: + + + location = /async { + keepalive_timeout 0; + content_by_lua ' + ngx.say("got the task!") + ngx.eof() -- descent HTTP client will close the connection at this point + -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... + '; + } + + +But if you create subrequests to access other locations configured by Nginx upstream modules, then you should configure those upstream modules to ignore client connection abortions if they are not by default. For example, by default the standard [HttpProxyModule](http://wiki.nginx.org/HttpProxyModule) will terminate both the subrequest and the main request as soon as the client closes the connection, so it is important to turn on the [proxy_ignore_client_abort](http://wiki.nginx.org/HttpProxyModule#proxy_ignore_client_abort) directive in your location block configured by [HttpProxyModule](http://wiki.nginx.org/HttpProxyModule): + + + proxy_ignore_client_abort on; + ngx.sleep --------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 7f9ae53bc3..a41d805f21 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.6.4] released on 9 September 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.5] released on 15 September 2012. = Synopsis = @@ -2699,7 +2699,26 @@ It is strongly recommended to combine the return statement with thi '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Explicitly specify the end of the response output stream. +Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". + +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: + + + location = /async { + keepalive_timeout 0; + content_by_lua ' + ngx.say("got the task!") + ngx.eof() -- descent HTTP client will close the connection at this point + -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... + '; + } + + +But if you create subrequests to access other locations configured by Nginx upstream modules, then you should configure those upstream modules to ignore client connection abortions if they are not by default. For example, by default the standard [[HttpProxyModule]] will terminate both the subrequest and the main request as soon as the client closes the connection, so it is important to turn on the [[HttpProxyModule#proxy_ignore_client_abort|proxy_ignore_client_abort]] directive in your location block configured by [[HttpProxyModule]]: + + + proxy_ignore_client_abort on; + == ngx.sleep == '''syntax:''' ''ngx.sleep(seconds)'' From 2e50b19433808048b4693caac5c406a704cfb9a5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 15 Sep 2012 21:23:22 -0700 Subject: [PATCH 0046/2239] updated valgrind.suppress for valgrind 3.8.0. --- valgrind.suppress | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/valgrind.suppress b/valgrind.suppress index d436c38d9e..6296fdd845 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -2,6 +2,13 @@ Memcheck:Param sendmsg(msg.msg_iov[0]) +fun:sendmsg +fun:ngx_write_channel +} +{ + +Memcheck:Param +sendmsg(msg.msg_iov[0]) fun:__sendmsg_nocancel fun:ngx_write_channel fun:ngx_pass_open_channel From 67f8bbbde3899f841e8d5416c4ac0bb3dc69a0cc Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 17 Sep 2012 11:48:04 -0700 Subject: [PATCH 0047/2239] removed the valgrind suppression rules for sendmsg/ngx_channel_write since we already fix these issues via the channel-uninit-params patch: https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.2.3-channel-uninit-params.patch --- valgrind.suppress | 83 +---------------------------------------------- 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/valgrind.suppress b/valgrind.suppress index 6296fdd845..9420ed2efc 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,27 +1,5 @@ { -Memcheck:Param -sendmsg(msg.msg_iov[0]) -fun:sendmsg -fun:ngx_write_channel -} -{ - -Memcheck:Param -sendmsg(msg.msg_iov[0]) -fun:__sendmsg_nocancel -fun:ngx_write_channel -fun:ngx_pass_open_channel -} -{ - -Memcheck:Param -sendmsg(msg.msg_iov[0]) -fun:__sendmsg_nocancel -fun:ngx_write_channel -} -{ - Memcheck:Leak fun:malloc fun:ngx_alloc @@ -40,46 +18,7 @@ fun:ngx_init_cycle fun:ngx_master_process_cycle fun:main } -{ - - Memcheck:Param - socketcall.sendmsg(msg.msg_iov[i]) - fun:sendmsg - fun:ngx_write_channel - fun:ngx_signal_worker_processes - fun:ngx_master_process_cycle - fun:main -} -{ - -Memcheck:Param -socketcall.sendmsg(msg.msg_iov[i]) -fun:__sendmsg_nocancel -fun:ngx_write_channel -fun:ngx_signal_worker_processes -fun:ngx_master_process_cycle -fun:main -} -{ - -Memcheck:Param -socketcall.sendmsg(msg.msg_iov[i]) -fun:__sendmsg_nocancel -fun:ngx_write_channel -fun:ngx_master_process_cycle -fun:main -} -{ - -Memcheck:Param -socketcall.sendmsg(msg.msg_iov[i]) -fun:__sendmsg_nocancel -fun:ngx_write_channel -fun:ngx_pass_open_channel -fun:ngx_start_worker_processes -fun:ngx_master_process_cycle -fun:main -} + { Memcheck:Cond @@ -426,16 +365,6 @@ fun:ngx_http_lua_ngx_echo fun:ngx_master_process_cycle fun:main } -{ - - Memcheck:Param - socketcall.sendmsg(msg.msg_iov[i]) - fun:__sendmsg_nocancel - fun:ngx_write_channel - fun:ngx_signal_worker_processes - fun:ngx_master_process_cycle - fun:main -} { Memcheck:Leak @@ -617,13 +546,3 @@ fun:ngx_http_lua_ngx_echo fun:ngx_palloc_block fun:ngx_palloc } -{ - - Memcheck:Param - sendmsg(msg.msg_iov[0]) - fun:__sendmsg_nocancel - fun:ngx_write_channel - fun:ngx_signal_worker_processes - fun:ngx_master_process_cycle - fun:main -} From d0d9140e118693ce3dfb5523ad2f6f5c428f2503 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 17 Sep 2012 20:13:07 -0700 Subject: [PATCH 0048/2239] optimize: tcpsock:send() now calls c->send() instead of ngx_output_chain(), which gives about 4src/tcp.c ~ 5src/tcp.c performance boost for a simple test case accessing redis for several times. --- src/ngx_http_lua_socket_tcp.c | 131 ++++++++++++++-------------------- src/ngx_http_lua_socket_tcp.h | 5 -- t/065-tcp-socket-timeout.t | 14 ++++ 3 files changed, 68 insertions(+), 82 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index f59acec362..67fe0ad777 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -795,7 +795,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, u->read_event_handler = ngx_http_lua_socket_connected_handler; c->sendfile &= r->connection->sendfile; - u->output.sendfile = c->sendfile; c->pool = r->pool; c->log = r->connection->log; @@ -809,10 +808,6 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, u->writer.last = &u->writer.out; #endif - u->writer.connection = c; - u->writer.limit = 0; - u->request_sent = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); coctx = ctx->cur_co_ctx; @@ -1482,7 +1477,6 @@ ngx_http_lua_socket_tcp_send(lua_State *L) ngx_http_request_t *r; u_char *p; size_t len; - ngx_http_core_loc_conf_t *clcf; ngx_chain_t *cl; ngx_http_lua_ctx_t *ctx; ngx_http_lua_socket_tcp_upstream_t *u; @@ -1589,30 +1583,10 @@ ngx_http_lua_socket_tcp_send(lua_State *L) u->request_bufs = cl; u->request_len = len; - u->request_sent = 0; u->ft_type = 0; /* mimic ngx_http_upstream_init_request here */ -#if 1 - u->writer.out = NULL; - u->writer.last = &u->writer.out; -#endif - - if (u->output.pool == NULL) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - u->output.alignment = clcf->directio_alignment; - u->output.pool = r->pool; - u->output.bufs.num = 1; - u->output.bufs.size = clcf->client_body_buffer_size; - u->output.output_filter = ngx_chain_writer; - u->output.filter_ctx = &u->writer; - u->output.tag = (ngx_buf_tag_t) &ngx_http_lua_module; - - u->writer.pool = r->pool; - } - #if 1 u->waiting = 0; #endif @@ -1921,9 +1895,10 @@ static ngx_int_t ngx_http_lua_socket_send(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) { - ngx_int_t rc; + ngx_int_t n; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; + ngx_buf_t *b; c = u->peer.connection; @@ -1932,67 +1907,78 @@ ngx_http_lua_socket_send(ngx_http_request_t *r, dd("lua connection log: %p", c->log); - rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs); + b = u->request_bufs->buf; - dd("output chain returned: %d", (int) rc); + for (;;) { + n = c->send(c, b->pos, b->last - b->pos); - u->request_sent = 1; + if (n >= 0) { + b->pos += n; - if (rc == NGX_ERROR) { - u->socket_errno = ngx_socket_errno; - ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); - return NGX_ERROR; - } + if (b->pos == b->last) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "lua tcp socket sent all the data"); - if (c->write->timer_set) { - ngx_del_timer(c->write); - } + if (c->write->timer_set) { + ngx_del_timer(c->write); + } - if (rc == NGX_AGAIN) { - u->write_event_handler = ngx_http_lua_socket_send_handler; - u->read_event_handler = ngx_http_lua_socket_dummy_handler; + 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; + } - ngx_add_timer(c->write, u->send_timeout); +#if defined(nginx_version) && nginx_version >= 1001004 + ngx_chain_update_chains(r->pool, +#else + ngx_chain_update_chains( +#endif + &ctx->free_bufs, &ctx->busy_bufs, + &u->request_bufs, + (ngx_buf_tag_t) &ngx_http_lua_module); - 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); - return NGX_ERROR; - } + u->write_event_handler = ngx_http_lua_socket_dummy_handler; - return NGX_AGAIN; - } + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); + return NGX_ERROR; + } + + ngx_http_lua_socket_handle_success(r, u); + return NGX_OK; + } - /* rc == NGX_OK */ + /* keep sending more data */ + continue; + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua tcp socket sent all the data: buffered 0x%d", - (int) c->buffered); + /* NGX_ERROR || NGX_AGAIN */ + break; + } - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { + if (n == NGX_ERROR) { + u->socket_errno = ngx_socket_errno; 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, -#else - ngx_chain_update_chains( -#endif - &ctx->free_bufs, &ctx->busy_bufs, &u->request_bufs, - (ngx_buf_tag_t) &ngx_http_lua_module); + /* n == NGX_AGAIN */ - u->request_sent = 0; - u->write_event_handler = ngx_http_lua_socket_dummy_handler; + u->write_event_handler = ngx_http_lua_socket_send_handler; + u->read_event_handler = ngx_http_lua_socket_dummy_handler; - 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_add_timer(c->write, u->send_timeout); + + 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); return NGX_ERROR; } - ngx_http_lua_socket_handle_success(r, u); - return NGX_OK; + return NGX_AGAIN; } @@ -3341,15 +3327,6 @@ ngx_http_lua_get_keepalive_peer(ngx_http_request_t *r, lua_State *L, u->reused = item->reused + 1; -#if 0 - u->writer.out = NULL; - u->writer.last = &u->writer.out; -#endif - - u->writer.connection = c; - u->writer.limit = 0; - u->request_sent = 0; - #if 1 u->write_event_handler = ngx_http_lua_socket_dummy_handler; u->read_event_handler = ngx_http_lua_socket_dummy_handler; diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index f54c63b034..f5a96707ce 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -68,9 +68,6 @@ struct ngx_http_lua_socket_tcp_upstream_s { ngx_uint_t ft_type; ngx_err_t socket_errno; - ngx_output_chain_ctx_t output; - ngx_chain_writer_ctx_t writer; - ngx_int_t (*input_filter)(void *data, ssize_t bytes); void *input_filter_ctx; @@ -81,8 +78,6 @@ struct ngx_http_lua_socket_tcp_upstream_s { ngx_uint_t reused; - unsigned request_sent:1; - unsigned waiting:1; unsigned eof:1; unsigned is_downstream:1; diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 8bc070ad8c..f7140fee86 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -396,6 +396,20 @@ lua tcp socket read timed out } --- 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 From 7d5d923400592ac588a3b6af1218fe8b4542ce70 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 11:42:15 -0700 Subject: [PATCH 0049/2239] docs: fixed the documenation for ngx.req.set_header and made it explicit that the modified request headers will be inherited by the subrequests. thanks James Hurst for reporting this nit. --- README | 7 +++++-- README.markdown | 3 ++- doc/HttpLuaModule.wiki | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README b/README index 03141ded7c..e63a05c868 100644 --- a/README +++ b/README @@ -2415,8 +2415,11 @@ Nginx API for Lua header_filter_by_lua*, body_filter_by_lua* Set the current request's request header named "header_name" to value - "header_value", overriding any existing ones. None of the current - request's subrequests will be affected. + "header_value", overriding any existing ones. + + By default, all the subrequests subsequently initiated by + ngx.location.capture and ngx.location.capture_multi will automatically + inherit the new header. Here is an example of setting the "Content-Length" header: diff --git a/README.markdown b/README.markdown index b090d0e5cc..a500dc563b 100644 --- a/README.markdown +++ b/README.markdown @@ -2274,7 +2274,8 @@ ngx.req.set_header **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua* Set the current request's request header named `header_name` to value `header_value`, overriding any existing ones. -None of the current request's subrequests will be affected. + +By default, all the subrequests subsequently initiated by [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) will automatically inherit the new header. Here is an example of setting the `Content-Length` header: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a41d805f21..55b5206910 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2208,7 +2208,8 @@ Removing the max_headers cap is strongly discouraged. '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua'' Set the current request's request header named header_name to value header_value, overriding any existing ones. -None of the current request's subrequests will be affected. + +By default, all the subrequests subsequently initiated by [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] will automatically inherit the new header. Here is an example of setting the Content-Length header: From 1fc023b26a313bb63a46c1b83cdcaff0a6992485 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 14:54:17 -0700 Subject: [PATCH 0050/2239] removed the declaration of the non-existent function ngx_http_lua_resume; also fixed a warning from clang. --- src/ngx_http_lua_coroutine.h | 1 - src/ngx_http_lua_util.c | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_coroutine.h b/src/ngx_http_lua_coroutine.h index b599d57b09..b3df27291a 100644 --- a/src/ngx_http_lua_coroutine.h +++ b/src/ngx_http_lua_coroutine.h @@ -8,7 +8,6 @@ void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L); -int ngx_http_lua_resume(lua_State *L, int nargs); #endif /* NGX_HTTP_LUA_COROUTINE_H */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index e38b086f74..26492a6a8f 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -102,10 +102,17 @@ ngx_http_lua_set_path(ngx_conf_t *cf, lua_State *L, int tab_idx, dd("tmp_path path: %s", tmp_path); - tmp_path = luaL_gsub(L, tmp_path, AUX_MARK, default_path); +#if (NGX_DEBUG) + tmp_path = +#else + (void) +#endif + luaL_gsub(L, tmp_path, AUX_MARK, default_path); +#if (NGX_DEBUG) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "lua setting lua package.%s to \"%s\"", fieldname, tmp_path); +#endif lua_remove(L, -2); From 213acb96ffe25aa2f007f4c19935b84e164f19da Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 17:19:55 -0700 Subject: [PATCH 0051/2239] refactor: removed the ctx->entry_co field and also made the coctx->co_status and coctx->flushing fields smaller. --- src/ngx_http_lua_accessby.c | 1 - src/ngx_http_lua_common.h | 11 ++++------- src/ngx_http_lua_contentby.c | 1 - src/ngx_http_lua_rewriteby.c | 1 - src/ngx_http_lua_util.c | 8 ++++---- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index e6989c5268..15ecdb62d4 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -254,7 +254,6 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entered_access_phase = 1; - ctx->entry_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 1875a90054..7cf08e57fc 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -213,8 +213,6 @@ struct ngx_http_lua_co_ctx_s { lua_State *co; ngx_http_lua_co_ctx_t *parent_co_ctx; - ngx_http_lua_co_status_t co_status; - ngx_http_cleanup_pt *cleanup; unsigned nsubreqs; /* number of subrequests of the @@ -231,9 +229,10 @@ struct ngx_http_lua_co_ctx_s { ngx_event_t sleep; /* used for ngx.sleep */ - unsigned flushing; /* :1 indicates whether the current - coroutine is waiting for - ngx.flush(true) */ + unsigned flushing:1; /* indicates whether the current + coroutine is waiting for + ngx.flush(true) */ + ngx_http_lua_co_status_t co_status:2; }; @@ -246,8 +245,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ - lua_State *entry_co; /* the entry Lua coroutine */ - /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ ngx_array_t *user_co_ctx; /* coroutine contexts for user coroutines */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 9b9f533f7b..736359550d 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -63,7 +63,6 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) lua_rawset(co, LUA_GLOBALSINDEX); /* }}} */ - ctx->entry_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 997ba7bcab..c65203966a 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -257,7 +257,6 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->entered_rewrite_phase = 1; - ctx->entry_co = co; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->entry_ref = co_ref; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 26492a6a8f..94fbbc5945 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -933,7 +933,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua coroutine: yield"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - if (ctx->cur_co_ctx->co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { /* entry coroutine yielded will be resumed * immediately */ @@ -976,7 +976,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - if (ctx->cur_co_ctx->co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { dd("hit! it is the entry"); lua_settop(L, 0); /* discard return values */ @@ -1075,7 +1075,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, trace = lua_tostring(L, -1); lua_pop(L, 1); - if (ctx->cur_co_ctx->co == ctx->entry_co) { + if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: %s: %s\n%s", err, msg, trace); @@ -2468,7 +2468,7 @@ ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx) ngx_uint_t i; ngx_http_lua_co_ctx_t *coctx; - if (L == ctx->entry_co) { + if (L == ctx->entry_co_ctx.co) { return &ctx->entry_co_ctx; } From cf474bcb9f3b86c68121b24d34974ffe87d533e2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 19:20:36 -0700 Subject: [PATCH 0052/2239] refactor: improved status code handling in content/access/rewrite_by_lua*. --- src/ngx_http_lua_accessby.c | 16 ++++------ src/ngx_http_lua_contentby.c | 58 +++++++++++++----------------------- src/ngx_http_lua_rewriteby.c | 6 +--- 3 files changed, 28 insertions(+), 52 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 15ecdb62d4..5f993874e1 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -98,7 +98,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); - return rc; + if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + return rc; + } + + return NGX_DECLINED; } if (llcf->force_read_body && !ctx->read_body_done) { @@ -279,7 +283,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_HTTP_SPECIAL_RESPONSE) { + if (rc == NGX_ERROR || rc >= NGX_OK) { return rc; } @@ -292,14 +296,6 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DONE; } - if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - if (rc == NGX_OK) { - return NGX_OK; - } - return NGX_DECLINED; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 736359550d..c80f6e68f4 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -19,6 +19,7 @@ ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; + ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; @@ -82,7 +83,24 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT; - return ngx_http_lua_run_thread(L, r, ctx, 0); + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } + + if (rc == NGX_DONE) { + return NGX_DONE; + } + + if (rc == NGX_AGAIN) { +#if defined(nginx_version) && nginx_version >= 8011 + r->main->count++; +#endif + return NGX_DONE; + } + + return NGX_OK; } @@ -236,24 +254,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)); - rc = ngx_http_lua_content_by_chunk(L, r); - - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - if (rc == NGX_DONE) { - return NGX_DONE; - } - - if (rc == NGX_AGAIN) { -#if defined(nginx_version) && nginx_version >= 8011 - r->main->count++; -#endif - return NGX_DONE; - } - - return NGX_OK; + return ngx_http_lua_content_by_chunk(L, r); } @@ -287,23 +288,6 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - rc = ngx_http_lua_content_by_chunk(L, r); - - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - if (rc == NGX_DONE) { - return NGX_DONE; - } - - if (rc == NGX_AGAIN) { -#if defined(nginx_version) && nginx_version >= 8011 - r->main->count++; -#endif - return NGX_DONE; - } - - return NGX_OK; + return ngx_http_lua_content_by_chunk(L, r); } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index c65203966a..a280d43b5c 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -280,7 +280,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) rc = ngx_http_lua_run_thread(L, r, ctx, 0); - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } @@ -293,10 +293,6 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DONE; } - if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - return NGX_DECLINED; } From 51a68ac94a9fad9a9db1806430c9a7f98896d885 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 20:07:33 -0700 Subject: [PATCH 0053/2239] bugfix: better error handling in ngx_http_lua_wev_handler. --- src/ngx_http_lua_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 94fbbc5945..564f347300 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1196,7 +1196,9 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) ngx_add_timer(wev, clcf->send_timeout); if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { - ngx_http_finalize_request(r, NGX_ERROR); + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, NGX_ERROR); + } return NGX_ERROR; } } @@ -1216,7 +1218,6 @@ 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); - return NGX_DONE; } return rc; @@ -1248,7 +1249,6 @@ 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); - return NGX_DONE; } return NGX_ERROR; From 3a7075dcd19c2c46f1b14ff8655a5bccfeb56453 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 20:24:02 -0700 Subject: [PATCH 0054/2239] added comments to the ngx_http_lua_run_thread function; also fixed a coding style issue. --- src/ngx_http_lua_util.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 564f347300..3dc9f19981 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -813,6 +813,15 @@ ngx_http_lua_request_cleanup(void *data) } +/* + * description: + * run a Lua coroutine specified by ctx->cur_co_ctx->co + * return value: + * NGX_AGAIN: I/O interruption: r->main->count intact + * NGX_DONE: I/O interruption: r->main->count already incremented by 1 + * NGX_ERROR: error + * >= 200 HTTP status code + */ ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int nret) @@ -1829,9 +1838,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); - if (rc == NGX_ERROR || - rc >= NGX_HTTP_SPECIAL_RESPONSE) - { + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } } From 946e907416369e2759b04ee99afbac6fa2d18ccd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 20 Sep 2012 22:52:33 -0700 Subject: [PATCH 0055/2239] bugfix: the "resume_handler" field of the subrequest ctx was not properly initialized. --- src/ngx_http_lua_subrequest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 17438fa254..2fb5f55378 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -502,9 +502,9 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) sr_ctx->entry_ref = LUA_NOREF; sr_ctx->ctx_ref = LUA_NOREF; + sr_ctx->resume_handler = ngx_http_lua_wev_handler; sr_ctx->capture = 1; - sr_ctx->index = index; psr_data->ctx = sr_ctx; From 639cc398fbb34f7abaac8d0bc70d1da3d50966e2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 21 Sep 2012 11:12:35 -0700 Subject: [PATCH 0056/2239] refactor: removed the unused function ngx_http_lua_has_inline_var. --- src/ngx_http_lua_util.c | 7 ------- src/ngx_http_lua_util.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 3dc9f19981..a206f7783e 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -291,13 +291,6 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, int ref) } -ngx_int_t -ngx_http_lua_has_inline_var(ngx_str_t *s) -{ - return (ngx_http_script_variables_count(s) != 0); -} - - u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 3413a97518..434d03300f 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -65,8 +65,6 @@ lua_State * ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l, void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *l, int ref); -ngx_int_t ngx_http_lua_has_inline_var(ngx_str_t *s); - u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len); ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, From 681f0dd61d2e916ed1245e9535faa466103c9577 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 21 Sep 2012 11:22:24 -0700 Subject: [PATCH 0057/2239] refactor: massive coding style fixes. --- src/ngx_http_lua_util.c | 70 +++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a206f7783e..3ac1a62429 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -51,15 +51,15 @@ char ngx_http_lua_request_key; static char ngx_http_lua_coroutines_key; static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx); + ngx_http_lua_ctx_t *ctx); static void ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L); static void ngx_http_lua_init_globals(ngx_conf_t *cf, lua_State *L); 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); + const char *fieldname, const char *path, const char *default_path); static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref); + ngx_http_lua_ctx_t *ctx, int entry_ref); static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref); + ngx_http_lua_ctx_t *ctx, int entry_ref); static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int entry_ref); static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, @@ -162,14 +162,15 @@ ngx_http_lua_new_state(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) if (!lua_istable(L, -1)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"package\" table does not exist"); + "the \"package\" table does not exist"); return NULL; } #ifdef LUA_DEFAULT_PATH # define LUA_DEFAULT_PATH_LEN (sizeof(LUA_DEFAULT_PATH) - 1) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "lua prepending default package.path with %s", LUA_DEFAULT_PATH); + "lua prepending default package.path with %s", + LUA_DEFAULT_PATH); lua_pushliteral(L, LUA_DEFAULT_PATH ";"); /* package default */ lua_getfield(L, -2, "path"); /* package default old */ @@ -181,7 +182,8 @@ ngx_http_lua_new_state(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) #ifdef LUA_DEFAULT_CPATH # define LUA_DEFAULT_CPATH_LEN (sizeof(LUA_DEFAULT_CPATH) - 1) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "lua prepending default package.cpath with %s", LUA_DEFAULT_CPATH); + "lua prepending default package.cpath with %s", + LUA_DEFAULT_CPATH); lua_pushliteral(L, LUA_DEFAULT_CPATH ";"); /* package default */ lua_getfield(L, -2, "cpath"); /* package default old */ @@ -235,7 +237,7 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) lua_State *co; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua creating new thread"); + "lua creating new thread"); base = lua_gettop(L); @@ -280,7 +282,7 @@ void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, int ref) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua deleting thread"); + "lua deleting thread"); lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -438,7 +440,7 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ctx->eof = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua sending last buf of the response body"); + "lua sending last buf of the response body"); rc = ngx_http_send_special(r, NGX_HTTP_LAST); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -452,7 +454,7 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, if (ctx->buffering) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua buffering output bufs for the HTTP 1.0 request"); + "lua buffering output bufs for the HTTP 1.0 request"); for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { ll = &cl->next; @@ -480,7 +482,7 @@ ngx_http_lua_send_http10_headers(ngx_http_request_t *r, } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua sending HTTP 1.0 response headers"); + "lua sending HTTP 1.0 response headers"); if (r->header_only) { goto send; @@ -509,7 +511,7 @@ static void ngx_http_lua_init_registry(ngx_conf_t *cf, lua_State *L) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "lua initializing lua registry"); + "lua initializing lua registry"); /* {{{ register a table to anchor lua coroutines reliably: * {([int]ref) = [cort]} */ @@ -552,7 +554,7 @@ static void ngx_http_lua_init_globals(ngx_conf_t *cf, lua_State *L) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "lua initializing lua globals"); + "lua initializing lua globals"); #if defined(NDK) && NDK ngx_http_lua_inject_ndk_api(L); @@ -681,7 +683,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua reset ctx"); + "lua reset ctx"); if (ctx->entry_ref != LUA_NOREF) { ngx_http_lua_del_thread(r, L, ctx->entry_ref); @@ -771,7 +773,7 @@ ngx_http_lua_request_cleanup(void *data) if (llcf->log_handler == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua release ngx.ctx"); + "lua release ngx.ctx"); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -1212,8 +1214,8 @@ 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); + "lua wev handler flushing output: buffered 0x%uxd", + c->buffered); rc = ngx_http_output_filter(r, NULL); @@ -1258,8 +1260,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) if (ctx->flushing_coros) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua flush still waiting: buffered 0x%uxd", - c->buffered); + "lua flush still waiting: buffered 0x%uxd", + c->buffered); return NGX_DONE; } @@ -1730,8 +1732,8 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua thread initiated internal redirect to %V", - &ctx->exec_uri); + "lua thread initiated internal redirect to %V", + &ctx->exec_uri); ngx_http_lua_del_thread(r, L, entry_ref); ctx->entry_ref = LUA_NOREF; @@ -1741,9 +1743,9 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, if (ctx->exec_uri.data[0] == '@') { if (ctx->exec_args.len > 0) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "query strings %V ignored when exec'ing " - "named location %V", - &ctx->exec_args, &ctx->exec_uri); + "query strings %V ignored when exec'ing " + "named location %V", + &ctx->exec_args, &ctx->exec_uri); } r->write_event_handler = ngx_http_request_empty_handler; @@ -1809,8 +1811,8 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua thread aborting request with status %d", - ctx->exit_code); + "lua thread aborting request with status %d", + ctx->exit_code); #if 1 if (!ctx->headers_sent && ctx->exit_code >= NGX_HTTP_OK) { @@ -1864,7 +1866,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, while (lua_next(L, table) != 0) { if (lua_type(L, -2) != LUA_TSTRING) { luaL_error(L, "attempt to use a non-string key in the " - "\"args\" option table"); + "\"args\" option table"); return; } @@ -1904,7 +1906,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (value == NULL) { luaL_error(L, "attempt to use %s as query arg value", - luaL_typename(L, -1)); + luaL_typename(L, -1)); return; } @@ -1927,7 +1929,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, default: luaL_error(L, "attempt to use %s as query arg value", - luaL_typename(L, -1)); + luaL_typename(L, -1)); return; } @@ -2073,8 +2075,8 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int entry_ref) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua thread aborting request with URI rewrite jump: \"%V?%V\"", - &r->uri, &r->args); + "lua thread aborting request with URI rewrite jump: " + "\"%V?%V\"", &r->uri, &r->args); ngx_http_lua_del_thread(r, L, entry_ref); ctx->entry_ref = LUA_NOREF; @@ -2211,8 +2213,8 @@ ngx_http_lua_chains_get_free_buf(ngx_log_t *log, ngx_pool_t *p, b = cl->buf; if ((size_t) (b->end - b->start) >= len) { ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0, - "lua reuse free buf memory %O >= %uz, cl:%p, p:%p", - (off_t) (b->end - b->start), len, cl, b->start); + "lua reuse free buf memory %O >= %uz, cl:%p, p:%p", + (off_t) (b->end - b->start), len, cl, b->start); b->pos = b->start; b->last = b->start; From 903a3e55cffeff47f5efeb01ac53882ca1b8ac8e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 21 Sep 2012 11:26:26 -0700 Subject: [PATCH 0058/2239] refactor: even more coding style fixes. --- src/ngx_http_lua_util.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 3ac1a62429..1acb8b188c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -85,7 +85,7 @@ enum { 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) + const char *fieldname, const char *path, const char *default_path) { const char *tmp_path; const char *prefix; @@ -332,7 +332,7 @@ ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len) ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx) + ngx_http_lua_ctx_t *ctx) { ngx_int_t rc; @@ -364,7 +364,7 @@ ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, - ngx_chain_t *in) + ngx_chain_t *in) { ngx_int_t rc; ngx_chain_t *cl; @@ -471,7 +471,7 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, static ngx_int_t ngx_http_lua_send_http10_headers(ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx) + ngx_http_lua_ctx_t *ctx) { size_t size; ngx_chain_t *cl; @@ -626,7 +626,7 @@ 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 **chain, ngx_chain_t *in) + ngx_chain_t **chain, ngx_chain_t *in) { ngx_chain_t *cl, **ll; size_t len; @@ -680,7 +680,7 @@ ngx_http_lua_add_copy_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, - ngx_http_lua_ctx_t *ctx) + ngx_http_lua_ctx_t *ctx) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua reset ctx"); @@ -819,7 +819,7 @@ 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, int nret) { ngx_http_lua_co_ctx_t *next_coctx; int rv, nrets; @@ -1569,7 +1569,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* XXX we also decode '+' to ' ' */ void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, - ngx_uint_t type) + ngx_uint_t type) { u_char *d, *s, ch, c, decoded; enum { @@ -1727,7 +1727,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx, int entry_ref) { ngx_int_t rc; @@ -1806,7 +1806,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx, int entry_ref) { ngx_int_t rc; @@ -1844,7 +1844,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, void ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, - int table, ngx_str_t *args) + int table, ngx_str_t *args) { u_char *key; size_t key_len; @@ -2072,7 +2072,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx, int entry_ref) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua thread aborting request with URI rewrite jump: " @@ -2090,7 +2090,7 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, /* XXX ngx_open_and_stat_file is static in the core. sigh. */ ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, - ngx_log_t *log) + ngx_log_t *log) { ngx_fd_t fd; ngx_file_info_t fi; @@ -2278,7 +2278,7 @@ ngx_http_lua_chains_get_free_buf(ngx_log_t *log, ngx_pool_t *p, static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, - ngx_http_lua_co_ctx_t *coctx) + ngx_http_lua_co_ctx_t *coctx) { int base; int level = 0, count = 0; From 6d854044cf08a3b71600c79f6f9f88407524fff6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 01:31:13 -0700 Subject: [PATCH 0059/2239] feature: first prototype for the ngx.thread API (aka the lightweight thread API for ngx_lua) that passes the first bunch of tests. --- .gitignore | 1 + config | 2 + dtrace/ngx_lua_provider.d | 10 +- src/ngx_http_lua_accessby.c | 9 +- src/ngx_http_lua_common.h | 42 ++- src/ngx_http_lua_contentby.c | 86 ++++++- src/ngx_http_lua_coroutine.c | 25 +- src/ngx_http_lua_coroutine.h | 3 + src/ngx_http_lua_output.c | 11 +- src/ngx_http_lua_probe.h | 14 +- src/ngx_http_lua_req_body.c | 9 +- src/ngx_http_lua_rewriteby.c | 9 +- src/ngx_http_lua_sleep.c | 11 +- src/ngx_http_lua_socket_tcp.c | 9 +- src/ngx_http_lua_socket_udp.c | 9 +- src/ngx_http_lua_subrequest.c | 15 +- src/ngx_http_lua_uthread.c | 61 +++++ src/ngx_http_lua_uthread.h | 24 ++ src/ngx_http_lua_util.c | 357 ++++++++++++++++++-------- src/ngx_http_lua_util.h | 26 +- t/034-match.t | 2 +- t/044-req-body.t | 2 +- t/062-count.t | 8 +- t/073-backtrace.t | 2 +- t/091-coroutine.t | 4 +- t/093-uthread.t | 469 ++++++++++++++++++++++++++++++++++ 26 files changed, 1042 insertions(+), 178 deletions(-) create mode 100644 src/ngx_http_lua_uthread.c create mode 100644 src/ngx_http_lua_uthread.h create mode 100644 t/093-uthread.t diff --git a/.gitignore b/.gitignore index 2c6a20aea5..66bb089f26 100644 --- a/.gitignore +++ b/.gitignore @@ -148,6 +148,7 @@ src/method.[ch] tre src/phase.[ch] src/probe.h +src/uthread.[ch] *.plist lua Makefile diff --git a/config b/config index 74d8c6be28..eeb3bf37c4 100644 --- a/config +++ b/config @@ -185,6 +185,7 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_socket_udp.c \ $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_DEPS="$NGX_ADDON_DEPS \ @@ -234,6 +235,7 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_req_method.h \ $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 \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index c336b29e75..784b829f78 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -20,8 +20,7 @@ provider nginx_lua { void *parent, void *child); /* lua_State *L */ - probe http__lua__entry__coroutine__yield(ngx_http_request_t *r, - void *L); + probe http__lua__thread__yield(ngx_http_request_t *r, void *L); /* ngx_http_lua_socket_tcp_upstream_t *u */ probe http__lua__socket__tcp__send__start(ngx_http_request_t *r, @@ -34,6 +33,13 @@ provider nginx_lua { /* ngx_http_lua_socket_tcp_upstream_t *u */ probe http__lua__socket__tcp__setkeepalive__buf__unread( ngx_http_request_t *r, void *u, u_char *data, size_t len); + + /* lua_State *creator, lua_State *newthread */ + probe http__lua__user__thread__create(ngx_http_request_t *r, + void *creator, void *newthread); + + /* lua_State *thread */ + probe http__lua__thread__delete(ngx_http_request_t *r, void *thread); }; diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 5f993874e1..4f7d7545ac 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -218,6 +218,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; ngx_int_t rc; lua_State *co; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; @@ -260,7 +261,7 @@ 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->entry_ref = co_ref; + ctx->cur_co_ctx->co_ref = co_ref; /* }}} */ @@ -279,6 +280,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_ACCESS; + c = r->connection; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); dd("returned %d", (int) rc); @@ -288,12 +291,12 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, L, r, ctx); } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, L, r, ctx); } return NGX_DECLINED; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 7cf08e57fc..2f9286460f 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -192,7 +192,8 @@ typedef struct { typedef enum { NGX_HTTP_LUA_USER_CORO_NOP = 0, NGX_HTTP_LUA_USER_CORO_RESUME = 1, - NGX_HTTP_LUA_USER_CORO_YIELD = 2 + NGX_HTTP_LUA_USER_CORO_YIELD = 2, + NGX_HTTP_LUA_USER_THREAD_RESUME = 3 } ngx_http_lua_user_coro_op_t; @@ -200,11 +201,18 @@ typedef enum { NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */ NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */ NGX_HTTP_LUA_CO_NORMAL = 2, /* coroutine normal */ - NGX_HTTP_LUA_CO_DEAD = 3, /* coroutine dead */ + NGX_HTTP_LUA_CO_DEAD = 3 /* coroutine dead */ } ngx_http_lua_co_status_t; -typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; +typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t; + +typedef struct ngx_http_lua_posted_thread_s ngx_http_lua_posted_thread_t; + +struct ngx_http_lua_posted_thread_s { + ngx_http_lua_co_ctx_t *co_ctx; + ngx_http_lua_posted_thread_t *next; +}; struct ngx_http_lua_co_ctx_s { @@ -227,12 +235,20 @@ struct ngx_http_lua_co_ctx_s { unsigned pending_subreqs; /* number of subrequests being waited */ - ngx_event_t sleep; /* used for ngx.sleep */ + ngx_event_t sleep; /* used for ngx.sleep */ + + int co_ref; /* reference to anchor the thread + coroutines (entry coroutine and user + threads) in the Lua registry, + preventing the thread coroutine + from beging collected by the + Lua GC */ - unsigned flushing:1; /* indicates whether the current - coroutine is waiting for - ngx.flush(true) */ - ngx_http_lua_co_status_t co_status:2; + ngx_http_lua_co_status_t co_status:2; /* the current coroutine's status */ + + unsigned flushing:1; /* indicates whether the current + coroutine is waiting for + ngx.flush(true) */ }; @@ -252,12 +268,6 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the entry coroutine */ - int entry_ref; /* reference to anchor the entry - coroutine in the lua registry, - preventing the entry coroutine - from beging collected by the - Lua GC */ - int ctx_ref; /* reference to anchor request ctx data in lua registry */ @@ -265,6 +275,8 @@ typedef struct ngx_http_lua_ctx_s { unsigned flushing_coros; /* number of coroutines waiting on ngx.flush(true) */ + unsigned uthreads; /* number of active user threads */ + ngx_chain_t *out; /* buffered output chain for HTTP 1.0 */ ngx_chain_t *free_bufs; ngx_chain_t *busy_bufs; @@ -289,6 +301,8 @@ typedef struct ngx_http_lua_ctx_s { subrequest in its parent request */ + ngx_http_lua_posted_thread_t *posted_threads; + 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 c80f6e68f4..e7fca54ced 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -5,14 +5,17 @@ #endif #include "ddebug.h" -#include + #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_exception.h" #include "ngx_http_lua_cache.h" +#include "ngx_http_lua_probe.h" 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 @@ -66,7 +69,7 @@ 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->entry_ref = co_ref; + ctx->cur_co_ctx->co_ref = co_ref; /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { @@ -89,15 +92,12 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) return rc; } - if (rc == NGX_DONE) { - return NGX_DONE; + if (rc == NGX_AGAIN) { + return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } - if (rc == NGX_AGAIN) { -#if defined(nginx_version) && nginx_version >= 8011 - r->main->count++; -#endif - return NGX_DONE; + if (rc == NGX_DONE) { + return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } return NGX_OK; @@ -202,9 +202,7 @@ ngx_http_lua_content_phase_post_read(ngx_http_request_t *r) ngx_http_finalize_request(r, ngx_http_lua_content_handler(r)); } else { -#if defined(nginx_version) && nginx_version >= 8011 r->main->count--; -#endif } } @@ -291,3 +289,69 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) return ngx_http_lua_content_by_chunk(L, 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 rc; + ngx_http_lua_posted_thread_t *pt; + + for ( ;; ) { + pt = ctx->posted_threads; + if (pt == NULL) { + goto done; + } + + ctx->posted_threads = pt->next; + + if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) { + continue; + } + + ctx->cur_co_ctx = pt->co_ctx; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_AGAIN) { + continue; + } + + if (rc == NGX_DONE) { + n++; + continue; + } + + if (rc == NGX_OK) { + while (n > 0) { + ngx_http_finalize_request(r, NGX_DONE); + n--; + } + + return NGX_OK; + } + + /* rc == NGX_ERROR || rc > NGX_OK */ + + return rc; + } + +done: + if (n == 1) { + return NGX_DONE; + } + + if (n == 0) { + r->main->count++; + return NGX_DONE; + } + + /* n > 1 */ + + do { + ngx_http_finalize_request(r, NGX_DONE); + } while (--n > 1); + + return NGX_DONE; +} + diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 1655cbf868..23a7d86d80 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -27,8 +27,17 @@ static const char * ngx_http_lua_co_status_names[] = {"running", "suspended", "normal", "dead"}; + static int ngx_http_lua_coroutine_create(lua_State *L) +{ + return ngx_http_lua_coroutine_create_helper(L, NULL, NULL, NULL); +} + + +int +ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, + ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx) { lua_State *mt; /* the main thread */ lua_State *co; /* new coroutine to be created */ @@ -87,6 +96,18 @@ ngx_http_lua_coroutine_create(lua_State *L) lua_pushvalue(L, 1); /* copy entry function to top of L*/ lua_xmove(L, co, 1); /* move entry function from L to co */ + if (pcoctx) { + *pcoctx = coctx; + } + + if (pctx) { + *pctx = ctx; + } + + if (pr) { + *pr = r; + } + return 1; /* return new coroutine to Lua */ } @@ -184,12 +205,12 @@ ngx_http_lua_coroutine_yield(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD; - coctx = ctx->cur_co_ctx; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; + ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD; + if (coctx->parent_co_ctx) { dd("set coroutine to running"); coctx->parent_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; diff --git a/src/ngx_http_lua_coroutine.h b/src/ngx_http_lua_coroutine.h index b3df27291a..49a5f5ebf3 100644 --- a/src/ngx_http_lua_coroutine.h +++ b/src/ngx_http_lua_coroutine.h @@ -9,6 +9,9 @@ void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L); +int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, + ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx); + #endif /* NGX_HTTP_LUA_COROUTINE_H */ diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index d0212f9042..75aa7cb9c7 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -684,24 +684,29 @@ ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { ngx_int_t rc; + ngx_connection_t *c; ngx_http_lua_main_conf_t *lmcf; lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_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); return NGX_DONE; diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index 8fff85a1d5..7f2176d38b 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -35,8 +35,8 @@ #define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) \ NGINX_LUA_HTTP_LUA_USER_COROUTINE_YIELD(r, parent, child) -#define ngx_http_lua_probe_entry_coroutine_yield(r, L) \ - NGINX_LUA_HTTP_LUA_ENTRY_COROUTINE_YIELD(r, L) +#define ngx_http_lua_probe_thread_yield(r, L) \ + NGINX_LUA_HTTP_LUA_THREAD_YIELD(r, L) #define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) \ NGINX_LUA_HTTP_LUA_SOCKET_TCP_SEND_START(r, u, data, len) @@ -47,6 +47,12 @@ #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len)\ NGINX_LUA_HTTP_LUA_SOCKET_TCP_SETKEEPALIVE_BUF_UNREAD(r, u, data, len) +#define ngx_http_lua_probe_user_thread_create(r, creator, newthread) \ + NGINX_LUA_HTTP_LUA_USER_THREAD_CREATE(r, creator, newthread) + +#define ngx_http_lua_probe_thread_delete(r, thread) \ + NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread) + #else /* !(NGX_DTRACE) */ #define ngx_http_lua_probe_info(s) @@ -55,10 +61,12 @@ #define ngx_http_lua_probe_user_coroutine_create(r, parent, child) #define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) #define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) -#define ngx_http_lua_probe_entry_coroutine_yield(r, L) +#define ngx_http_lua_probe_thread_yield(r, L) #define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) #define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len) +#define ngx_http_lua_probe_user_thread_create(r, creator, newthread) +#define ngx_http_lua_probe_thread_delete(r, thread) #endif diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 98d3873582..5f1fc22ad9 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -1078,6 +1078,7 @@ static ngx_int_t ngx_http_lua_read_body_resume(ngx_http_request_t *r) { ngx_int_t rc; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_main_conf_t *lmcf; @@ -1087,18 +1088,20 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index a280d43b5c..a29adbe7b7 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -217,6 +217,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; lua_State *co; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_int_t rc; @@ -259,7 +260,7 @@ 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->entry_ref = co_ref; + ctx->cur_co_ctx->co_ref = co_ref; /* }}} */ @@ -278,6 +279,8 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE; + c = r->connection; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc > NGX_OK) { @@ -285,12 +288,12 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, L, r, ctx); } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, L, r, ctx); } return NGX_DECLINED; diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 401f8270ac..62e44be883 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -119,6 +119,8 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args); + dd("sleep timer set: %d", (int) coctx->sleep.timer_set); + if (coctx->sleep.timer_set) { dd("deleting timer for lua_sleep"); ngx_del_timer(&coctx->sleep); @@ -167,6 +169,7 @@ ngx_http_lua_co_cleanup(void *data) static ngx_int_t ngx_http_lua_sleep_resume(ngx_http_request_t *r) { + ngx_connection_t *c; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_main_conf_t *lmcf; @@ -180,18 +183,20 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 67fe0ad777..47dc0edb49 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3798,6 +3798,7 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) { int nret; ngx_int_t rc; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_main_conf_t *lmcf; @@ -3835,18 +3836,20 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) return NGX_DONE; } + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c,lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index e31ea153ee..0f79cf717b 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1359,6 +1359,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) { int nret; ngx_int_t rc; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_main_conf_t *lmcf; @@ -1394,18 +1395,20 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) return NGX_DONE; } + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_finalize_request(r, NGX_DONE); + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 2fb5f55378..c0d28025d9 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -500,9 +500,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) * sr_ctx->free = NULL */ - sr_ctx->entry_ref = LUA_NOREF; - sr_ctx->ctx_ref = LUA_NOREF; - sr_ctx->resume_handler = ngx_http_lua_wev_handler; + ngx_http_lua_init_ctx(sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; @@ -1415,6 +1413,7 @@ static ngx_int_t ngx_http_lua_subrequest_resume(ngx_http_request_t *r) { ngx_int_t rc; + ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_main_conf_t *lmcf; @@ -1447,20 +1446,24 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) coctx->sr_bodies = NULL; #endif + c = r->connection; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, coctx->nsubreqs); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return NGX_DONE; + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); } if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return NGX_DONE; + ngx_http_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); return NGX_DONE; diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c new file mode 100644 index 0000000000..338395ab4b --- /dev/null +++ b/src/ngx_http_lua_uthread.c @@ -0,0 +1,61 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_uthread.h" +#include "ngx_http_lua_coroutine.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_probe.h" + + +static int ngx_http_lua_uthread_create(lua_State *L); + + +void +ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) +{ + /* new thread table */ + lua_newtable(L); + + lua_pushcfunction(L, ngx_http_lua_uthread_create); + lua_setfield(L, -2, "create"); + + lua_setfield(L, -2, "thread"); +} + + +static int +ngx_http_lua_uthread_create(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx = NULL; + + ngx_http_lua_coroutine_create_helper(L, &r, &ctx, &coctx); + + /* anchor the newly created coroutine into the Lua registry */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, -3); + coctx->co_ref = luaL_ref(L, -2); + lua_pop(L, 1); + + ctx->uthreads++; + + coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + ctx->co_op = NGX_HTTP_LUA_USER_THREAD_RESUME; + + if (ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx) != NGX_OK) { + return luaL_error(L, "out of memory"); + } + + ctx->cur_co_ctx = coctx; + + ngx_http_lua_probe_user_thread_create(r, L, coctx->co); + + return lua_yield(L, 0); +} + diff --git a/src/ngx_http_lua_uthread.h b/src/ngx_http_lua_uthread.h new file mode 100644 index 0000000000..1d7cc6aacd --- /dev/null +++ b/src/ngx_http_lua_uthread.h @@ -0,0 +1,24 @@ +#ifndef NGX_HTTP_LUA_UTHREAD_H +#define NGX_HTTP_LUA_UTHREAD_H + + +#include "ngx_http_lua_common.h" + + +#define ngx_http_lua_is_thread(ctx) \ + ((ctx)->cur_co_ctx->co_ref != LUA_NOREF) + + +#define ngx_http_lua_is_entry_thread(ctx) \ + ((ctx)->cur_co_ctx == &ctx->entry_co_ctx) + + +#define ngx_http_lua_entry_thread_alive(ctx) \ + ((ctx)->entry_co_ctx.co_ref != LUA_NOREF) + + +void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L); + + +#endif /* NGX_HTTP_LUA_UTHREAD_H */ + diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1acb8b188c..cb1b74f17a 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -38,6 +38,7 @@ #include "ngx_http_lua_logby.h" #include "ngx_http_lua_phase.h" #include "ngx_http_lua_probe.h" +#include "ngx_http_lua_uthread.h" char ngx_http_lua_code_cache_key; @@ -45,11 +46,9 @@ 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; -/* coroutine anchoring table key in Lua vm registry */ -static char ngx_http_lua_coroutines_key; - 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); @@ -57,17 +56,21 @@ static void ngx_http_lua_init_globals(ngx_conf_t *cf, lua_State *L); 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); static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref); + ngx_http_lua_ctx_t *ctx); static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref); + ngx_http_lua_ctx_t *ctx); static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int entry_ref); + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, ngx_http_lua_co_ctx_t *coctx); static void ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L); static void ngx_http_lua_inject_arg_api(lua_State *L); static int ngx_http_lua_param_get(lua_State *L); static int ngx_http_lua_param_set(lua_State *L); +static void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); +static void ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, + ngx_http_lua_ctx_t *ctx); #ifndef LUA_PATH_SEP @@ -246,53 +249,119 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) co = lua_newthread(L); - if (co) { - /* {{{ inherit coroutine's globals to main thread's globals table - * for print() function will try to find tostring() in current - * globals table. - */ - /* new globals table for coroutine */ - ngx_http_lua_create_new_global_table(co, 0, 0); + /* {{{ inherit coroutine's globals to main thread's globals table + * for print() function will try to find tostring() in current + * globals table. + */ + /* new globals table for coroutine */ + ngx_http_lua_create_new_global_table(co, 0, 0); - lua_createtable(co, 0, 1); - lua_pushvalue(co, LUA_GLOBALSINDEX); - lua_setfield(co, -2, "__index"); - lua_setmetatable(co, -2); + lua_createtable(co, 0, 1); + lua_pushvalue(co, LUA_GLOBALSINDEX); + lua_setfield(co, -2, "__index"); + lua_setmetatable(co, -2); - lua_replace(co, LUA_GLOBALSINDEX); - /* }}} */ + lua_replace(co, LUA_GLOBALSINDEX); + /* }}} */ - *ref = luaL_ref(L, -2); + *ref = luaL_ref(L, -2); - if (*ref == LUA_NOREF) { - lua_settop(L, base); /* restore main thread stack */ - return NULL; - } + if (*ref == LUA_NOREF) { + lua_settop(L, base); /* restore main thread stack */ + return NULL; } - /* pop coroutine reference on main thread's stack after anchoring it - * in registry */ - lua_pop(L, 1); - + lua_settop(L, base); return co; } -void -ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, int ref) +static void +ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx) { + if (coctx->co_ref == LUA_NOREF) { + return; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua deleting thread"); + "lua deleting lightweight thread"); lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - /* release reference to coroutine */ - luaL_unref(L, -1, ref); + ngx_http_lua_probe_thread_delete(r, coctx->co); + + luaL_unref(L, -1, coctx->co_ref); + coctx->co_ref = LUA_NOREF; + coctx->co_status = NGX_HTTP_LUA_CO_DEAD; + lua_pop(L, 1); } +static void +ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, + ngx_http_lua_ctx_t *ctx) +{ + int inited = 0; + int ref; + ngx_uint_t i; + ngx_http_lua_co_ctx_t *entry_coctx; + ngx_http_lua_co_ctx_t *cc; + + if (ctx->uthreads) { + /* release all pending user threads */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + inited = 1; + + cc = ctx->user_co_ctx->elts; + + for (i = 0; i < ctx->user_co_ctx->nelts; i++) { + + ref = cc[i].co_ref; + + if (ref != LUA_NOREF) { + ngx_http_lua_probe_thread_delete(r, cc[i].co); + + luaL_unref(L, -1, ref); + cc[i].co_ref = LUA_NOREF; + cc[i].co_status = NGX_HTTP_LUA_CO_DEAD; + ctx->uthreads--; + + if (ctx->uthreads == 0) { + break; + } + } + } + } + + /* release the reference to the entry thread */ + + entry_coctx = &ctx->entry_co_ctx; + + if (entry_coctx->co_ref != LUA_NOREF) { + if (!inited) { + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + inited = 1; + } + + ngx_http_lua_probe_thread_delete(r, entry_coctx->co); + + luaL_unref(L, -1, entry_coctx->co_ref); + entry_coctx->co_ref = LUA_NOREF; + entry_coctx->co_status = NGX_HTTP_LUA_CO_DEAD; + } + + if (inited) { + lua_pop(L, 1); + } +} + + u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len) { @@ -571,7 +640,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 */, 83 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 84 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); @@ -597,6 +666,7 @@ ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L) ngx_http_lua_inject_shdict_api(lmcf, 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_misc_api(L); @@ -685,10 +755,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua reset ctx"); - if (ctx->entry_ref != LUA_NOREF) { - ngx_http_lua_del_thread(r, L, ctx->entry_ref); - ctx->entry_ref = LUA_NOREF; - } + ngx_http_lua_del_all_threads(r, L, ctx); if (ctx->user_co_ctx) { ngx_array_destroy(ctx->user_co_ctx); @@ -697,6 +764,8 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_memzero(&ctx->entry_co_ctx, sizeof(ngx_http_lua_co_ctx_t)); + ctx->entry_co_ctx.co_ref = LUA_NOREF; + ctx->entered_rewrite_phase = 0; ctx->entered_access_phase = 0; ctx->entered_content_phase = 0; @@ -783,28 +852,9 @@ ngx_http_lua_request_cleanup(void *data) } } - if (ctx->entry_ref == LUA_NOREF) { - return; - } - - lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_rawgeti(L, -1, ctx->entry_ref); - - if (lua_isthread(L, -1)) { - /* coroutine not finished yet, force quit */ - ngx_http_lua_del_thread(r, L, ctx->entry_ref); - ctx->entry_ref = LUA_NOREF; + /* threads not cleaned up yet */ - } else { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua internal error: not a thread object for the " - "current coroutine"); - - luaL_unref(L, -2, ctx->entry_ref); - } - - lua_pop(L, 2); + ngx_http_lua_del_all_threads(r, L, ctx); } @@ -886,16 +936,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua thread yielded"); if (r->uri_changed) { - return ngx_http_lua_handle_rewrite_jump(L, r, ctx, - ctx->entry_ref); + return ngx_http_lua_handle_rewrite_jump(L, r, ctx); } if (ctx->exited) { - return ngx_http_lua_handle_exit(L, r, ctx, ctx->entry_ref); + return ngx_http_lua_handle_exit(L, r, ctx); } if (ctx->exec_uri.len) { - return ngx_http_lua_handle_exec(L, r, ctx, ctx->entry_ref); + return ngx_http_lua_handle_exec(L, r, ctx); } /* @@ -911,6 +960,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, return NGX_AGAIN; + case NGX_HTTP_LUA_USER_THREAD_RESUME: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua user thread resume"); + + ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; + + break; + case NGX_HTTP_LUA_USER_CORO_RESUME: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua coroutine: resume"); @@ -937,12 +995,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua coroutine: yield"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { - /* entry coroutine yielded will be resumed - * immediately */ - ngx_http_lua_probe_entry_coroutine_yield(r, - ctx->cur_co_ctx->co); + if (ctx->cur_co_ctx->co_ref != LUA_NOREF) { + /* threads yielded will be resumed immediately */ + + ngx_http_lua_probe_thread_yield(r, ctx->cur_co_ctx->co); lua_settop(ctx->cur_co_ctx->co, 0); nrets = 0; @@ -980,30 +1037,44 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { - dd("hit! it is the entry"); + if (ngx_http_lua_is_thread(ctx)) { + /* a lightweight thread is terminated successfully */ lua_settop(L, 0); /* discard return values */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua entry thread ended normally"); + "lua lightweight thread ended normally"); - /* the entry thread was dead, delete it */ - ngx_http_lua_del_thread(r, L, ctx->entry_ref); - ctx->entry_ref = LUA_NOREF; + if (ngx_http_lua_is_entry_thread(ctx)) { + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); - if (ctx->entered_content_phase) { - rc = ngx_http_lua_send_chain_link(r, ctx, - NULL /* last_buf */); + if (ctx->uthreads) { + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } - if (rc == NGX_ERROR - || rc >= NGX_HTTP_SPECIAL_RESPONSE) - { - return rc; + /* all user threads terminated already */ + goto done; + } + + /* being a user thread */ + + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); + ctx->uthreads--; + + if (ctx->uthreads == 0) { + if (ngx_http_lua_entry_thread_alive(ctx)) { + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; } + + /* all threads terminated already */ + goto done; } - return NGX_OK; + /* some other user threads still running */ + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; } /* being a user coroutine that has a parent */ @@ -1079,16 +1150,14 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, trace = lua_tostring(L, -1); lua_pop(L, 1); - if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { + if (ngx_http_lua_is_thread(ctx)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua handler aborted: %s: %s\n%s", err, msg, - trace); + "lua thread aborted: %s: %s\n%s", + err, msg, trace); lua_settop(L, 0); - ngx_http_lua_del_thread(r, L, ctx->entry_ref); - ctx->entry_ref = LUA_NOREF; - + ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(r); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1142,15 +1211,25 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, no_parent: lua_settop(L, 0); - ngx_http_lua_del_thread(r, L, ctx->entry_ref); - ctx->entry_ref = LUA_NOREF; - + ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(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; + +done: + if (ctx->entered_content_phase) { + rc = ngx_http_lua_send_chain_link(r, ctx, + NULL /* last_buf */); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + } + + return NGX_OK; } @@ -1727,7 +1806,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx) { ngx_int_t rc; @@ -1735,9 +1814,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, "lua thread initiated internal redirect to %V", &ctx->exec_uri); - ngx_http_lua_del_thread(r, L, entry_ref); - ctx->entry_ref = LUA_NOREF; - + ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(r); if (ctx->exec_uri.data[0] == '@') { @@ -1806,7 +1883,7 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx) { ngx_int_t rc; @@ -1820,9 +1897,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, } #endif - ngx_http_lua_del_thread(r, L, entry_ref); - ctx->entry_ref = LUA_NOREF; - + ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(r); if ((ctx->exit_code == NGX_OK @@ -1830,8 +1905,7 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, || (ctx->exit_code >= NGX_HTTP_OK && ctx->exit_code < NGX_HTTP_SPECIAL_RESPONSE)) { - 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 */); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; @@ -2072,14 +2146,13 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, - ngx_http_lua_ctx_t *ctx, int entry_ref) + ngx_http_lua_ctx_t *ctx) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua thread aborting request with URI rewrite jump: " "\"%V?%V\"", &r->uri, &r->args); - ngx_http_lua_del_thread(r, L, entry_ref); - ctx->entry_ref = LUA_NOREF; + ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(r); @@ -2511,6 +2584,82 @@ ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t)); + + coctx->co_ref = LUA_NOREF; + return coctx; } + +/* this is for callers other than the content handler */ +ngx_int_t +ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_http_lua_posted_thread_t *pt; + + for ( ;; ) { + if (c->destroyed) { + return NGX_DONE; + } + + pt = ctx->posted_threads; + if (pt == NULL) { + return NGX_DONE; + } + + ctx->posted_threads = pt->next; + + if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) { + continue; + } + + ctx->cur_co_ctx = pt->co_ctx; + + rc = ngx_http_lua_run_thread(L, r, ctx, 0); + + if (rc == NGX_AGAIN) { + continue; + } + + if (rc == NGX_DONE) { + ngx_http_finalize_request(r, NGX_DONE); + continue; + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_http_finalize_request(r, rc); + } + + return rc; + } + + return NGX_DONE; +} + + +ngx_int_t +ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, + ngx_http_lua_co_ctx_t *coctx) +{ + ngx_http_lua_posted_thread_t **p; + ngx_http_lua_posted_thread_t *pt; + + pt = ngx_palloc(r->pool, sizeof(ngx_http_lua_posted_thread_t)); + if (pt == NULL) { + return NGX_ERROR; + } + + pt->co_ctx = coctx; + pt->next = NULL; + + for (p = &ctx->posted_threads; *p; p = &(*p)->next) { /* void */ } + + *p = pt; + + return NGX_OK; +} + diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 434d03300f..ab0fd094f2 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -35,6 +35,10 @@ 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; +/* coroutine anchoring table key in Lua VM registry */ +extern char ngx_http_lua_coroutines_key; + + #ifndef ngx_str_set #define ngx_str_set(str, text) \ (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text @@ -50,6 +54,7 @@ extern char ngx_http_lua_coroutine_parents_key; : (c) == NGX_HTTP_LUA_CONTEXT_HEADER_FILTER ? "header_filter_by_lua*" \ : "(unknown)") + #define ngx_http_lua_check_context(L, ctx, flags) \ if (!((ctx)->context & (flags))) { \ return luaL_error(L, "API disabled in the context of %s", \ @@ -63,8 +68,6 @@ lua_State * ngx_http_lua_new_state(ngx_conf_t *cf, lua_State * ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l, int *ref); -void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *l, int ref); - u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len); ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r, @@ -124,20 +127,31 @@ ngx_http_lua_co_ctx_t * ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_co_ctx_t * ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); +ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); + +ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); + + +#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; \ + ctx->resume_handler = ngx_http_lua_wev_handler; + static ngx_inline ngx_http_lua_ctx_t * ngx_http_lua_create_ctx(ngx_http_request_t *r) { ngx_http_lua_ctx_t *ctx; - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); + ctx = ngx_palloc(r->pool, sizeof(ngx_http_lua_ctx_t)); if (ctx == NULL) { return NULL; } - ctx->entry_ref = LUA_NOREF; - ctx->ctx_ref = LUA_NOREF; - ctx->resume_handler = ngx_http_lua_wev_handler; + ngx_http_lua_init_ctx(ctx); ngx_http_set_ctx(r, ctx, ngx_http_lua_module); return ctx; diff --git a/t/034-match.t b/t/034-match.t index 96d95b498d..cfe5501112 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -641,7 +641,7 @@ regex: (?:>[\w\s]*) --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log chop -lua handler 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]+") +lua 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]+") diff --git a/t/044-req-body.t b/t/044-req-body.t index d43ba77b3f..26e8b75229 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -564,7 +564,7 @@ qr/500 Internal Server Error/] --- error_code eval [200, 500] --- error_log eval -[qr{\[error\].*? lua handler aborted: runtime error: \[string "rewrite_by_lua"\]:3: stat\(\) "[^"]+/a\.txt" failed} +[qr{\[error\].*? lua thread aborted: runtime error: \[string "rewrite_by_lua"\]:3: stat\(\) "[^"]+/a\.txt" failed} ] diff --git a/t/062-count.t b/t/062-count.t index d6d109f1e0..11e5a42345 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 83 +ngx: 84 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 83 --- request GET /test --- response_body -83 +84 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 83 +n = 84 --- no_error_log [error] @@ -301,5 +301,5 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 83 +ngx. entry count: 84 diff --git a/t/073-backtrace.t b/t/073-backtrace.t index e98e363e6d..cd2cfb1233 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -59,7 +59,7 @@ attempt to call global 'lua_concat' GET /lua --- ignore_response --- error_log -lua handler aborted: runtime error: unknown reason +lua thread aborted: runtime error: unknown reason stack traceback: in function 'error' : in function 'bar' diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 0c907daf4c..9b3b280bc2 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -41,8 +41,8 @@ M(http-lua-user-coroutine-resume) { printf("resume %x in %x\n", c, p) } -M(http-lua-entry-coroutine-yield) { - println("entry coroutine yield") +M(http-lua-thread-yield) { + println("thread yield") } /* diff --git a/t/093-uthread.t b/t/093-uthread.t new file mode 100644 index 0000000000..f6c11849bf --- /dev/null +++ b/t/093-uthread.t @@ -0,0 +1,469 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +our $GCScript = <<'_EOC_'; +global ids, cur + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_init_request) { + delete ids + cur = 0 +} + +M(http-lua-user-thread-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create user thread %x in %x\n", c, p) +} + +M(http-lua-thread-delete) { + t = gen_id($arg2) + printf("delete thread %x\n", t) +} + +_EOC_ + +our $StapScript = <<'_EOC_'; +global ids, cur +global timers + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_init_request) { + delete ids + cur = 0 +} + +F(ngx_http_lua_co_cleanup) { + id = gen_id(@cast($data, "ngx_http_lua_co_ctx_t")->co) + printf("co cleanup called for thread %d\n", id) +} + +M(timer-add) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) +} + +M(timer-del) { + printf("delete timer %d\n", timers[$arg1]) +} + +M(timer-expire) { + printf("expire timer %d\n", timers[$arg1]) +} + +F(ngx_http_lua_sleep_handler) { + printf("sleep handler called\n") +} + +F(ngx_http_lua_run_thread) { + id = gen_id($ctx->cur_co_ctx->co) + printf("run thread %d\n", id) + #if (id == 1) { + #print_ubacktrace() + #} +} + +/* +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { + id = gen_id($L) + printf("lua resume %d\n", id) +} +*/ + +M(http-lua-user-thread-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create uthread %x in %x\n", c, p) +} + +M(http-lua-thread-delete) { + t = gen_id($arg2) + printf("delete thread %x\n", t) +} + +M(http-lua-user-coroutine-resume) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("resume %x in %x\n", c, p) +} + +M(http-lua-thread-yield) { + println("thread yield") +} + +/* +F(ngx_http_lua_coroutine_yield) { + printf("yield %x\n", gen_id($L)) +} +*/ + +M(http-lua-user-coroutine-yield) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("yield %x in %x\n", c, p) +} + +F(ngx_http_lua_atpanic) { + printf("lua atpanic(%d):", gen_id($L)) + print_ubacktrace(); +} + +F(ngx_http_lua_run_posted_threads) { + printf("run posted threads\n") +} + +F(ngx_http_finalize_request) { + printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); +} + +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + +F(ngx_http_lua_ngx_exec) { println("exec") } + +F(ngx_http_lua_ngx_exit) { println("exit") } +_EOC_ + +no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: simple user thread without I/O +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 2: two simple user threads without I/O +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("in thread 1") + end + + function g() + ngx.say("in thread 2") + end + + ngx.say("before 1") + ngx.thread.create(f) + ngx.say("after 1") + + ngx.say("before 2") + ngx.thread.create(g) + ngx.say("after 2") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +create user thread 3 in 1 +delete thread 3 +delete thread 1 + +--- response_body +before 1 +in thread 1 +after 1 +before 2 +in thread 2 +after 2 +--- no_error_log +[error] + + + +=== TEST 3: simple user thread with sleep +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before sleep") + ngx.sleep(0.1) + ngx.say("after sleep") + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before thread create +before sleep +after thread create +after sleep +--- no_error_log +[error] + + + +=== TEST 4: two simple user threads with sleep +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("1: before sleep") + ngx.sleep(0.2) + ngx.say("1: after sleep") + end + + function g() + ngx.say("2: before sleep") + ngx.sleep(0.1) + ngx.say("2: after sleep") + end + + ngx.say("1: before thread create") + ngx.thread.create(f) + ngx.say("1: after thread create") + + ngx.say("2: before thread create") + ngx.thread.create(g) + ngx.say("2: after thread create") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 3 +delete thread 2 + +--- response_body +1: before thread create +1: before sleep +1: after thread create +2: before thread create +2: before sleep +2: after thread create +2: after sleep +1: after sleep +--- no_error_log +[error] + + + +=== TEST 5: exit in user thread (entry still pending) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +before +hello in thread +--- no_error_log +[error] + + + +=== TEST 6: exit in user thread (entry already quits) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("exiting the user thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before +after +exiting the user thread +--- no_error_log +[error] + + + +=== TEST 7: exec in user thread (entry still pending) +--- config + location /lua { + content_by_lua ' + function f() + ngx.exec("/foo") + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("hello") + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 8: exec in user thread (entry already quits) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 9: error in user thread +--- config + location /lua { + content_by_lua ' + function f() + ngx.blah() + end + + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +lua thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) + From 12903c20dc5ddcfad434d350ea433d1d2ef3a65b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 01:32:03 -0700 Subject: [PATCH 0060/2239] test: enabled repeat_each(2) in 093-uthread.t. --- t/093-uthread.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/093-uthread.t b/t/093-uthread.t index f6c11849bf..b91cc5f1ca 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -3,7 +3,7 @@ use lib 'lib'; use Test::Nginx::Socket; -#repeat_each(2); +repeat_each(2); plan tests => repeat_each() * (blocks() * 4); From f02a7323db5795d92d3c1b8acbf7e1bfd6f09ada Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 12:23:31 -0700 Subject: [PATCH 0061/2239] added several (passing) tests for ngx.thread + ngx.location.capture. --- t/093-uthread.t | 243 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 5 deletions(-) diff --git a/t/093-uthread.t b/t/093-uthread.t index b91cc5f1ca..7d673a34d1 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -11,6 +11,7 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; our $GCScript = <<'_EOC_'; global ids, cur +global in_req = 0 function gen_id(k) { if (ids[k]) return ids[k] @@ -19,8 +20,15 @@ function gen_id(k) { } F(ngx_http_init_request) { - delete ids - cur = 0 + in_req++ + if (in_req == 1) { + delete ids + cur = 0 + } +} + +F(ngx_http_free_request) { + in_req-- } M(http-lua-user-thread-create) { @@ -39,6 +47,7 @@ _EOC_ our $StapScript = <<'_EOC_'; global ids, cur global timers +global in_req = 0 function gen_id(k) { if (ids[k]) return ids[k] @@ -47,8 +56,15 @@ function gen_id(k) { } F(ngx_http_init_request) { - delete ids - cur = 0 + in_req++ + if (in_req == 1) { + delete ids + cur = 0 + } +} + +F(ngx_http_free_request) { + in_req-- } F(ngx_http_lua_co_cleanup) { @@ -145,7 +161,7 @@ F(ngx_http_lua_ngx_exec) { println("exec") } F(ngx_http_lua_ngx_exit) { println("exit") } _EOC_ -no_shuffle(); +#no_shuffle(); no_long_string(); run_tests(); @@ -467,3 +483,220 @@ delete thread 1 --- error_log lua thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) + + +=== TEST 10: simple user threads doing a single subrequest (entry quits early) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before capture") + res = ngx.location.capture("/proxy") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + '; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/foo; + } + + location /foo { + echo_sleep 0.1; + echo -n hello world; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before thread create +before capture +after thread create +after capture: hello world +--- no_error_log +[error] + + + +=== TEST 11: simple user threads doing a single subrequest (entry also does a subrequest and quits early) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before thread create +before capture +after thread create +capture: hello bar +after capture: hello foo +--- no_error_log +[error] + + + +=== TEST 12: simple user threads doing a single subrequest (entry also does a subrequest and quits late) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +before thread create +before capture +after thread create +after capture: hello foo +capture: hello bar +--- no_error_log +[error] + + + +=== TEST 13: two simple user threads doing single subrequests (entry also does a subrequest and quits between) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("f: before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("f: after capture: ", res.body) + end + + function g() + ngx.say("g: before capture") + local res = ngx.location.capture("/proxy?bah") + ngx.say("g: after capture: ", res.body) + end + + ngx.say("before thread 1 create") + ngx.thread.create(f) + ngx.say("after thread 1 create") + + ngx.say("before thread 2 create") + ngx.thread.create(g) + ngx.say("after thread 2 create") + + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } + + location /bah { + echo_sleep 0.3; + echo -n hello bah; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +create user thread 3 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before thread 1 create +f: before capture +after thread 1 create +before thread 2 create +g: before capture +after thread 2 create +f: after capture: hello foo +capture: hello bar +g: after capture: hello bah +--- no_error_log +[error] + From 377bcd37893c804bcb1241b097a556cf4931382e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 12:26:06 -0700 Subject: [PATCH 0062/2239] updated docs to reflect recent changes. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index e63a05c868..5140fa0de8 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.6.5 - () released on 15 + This document describes ngx_lua v0.6.6 + () released on 20 September 2012. Synopsis diff --git a/README.markdown b/README.markdown index a500dc563b..a1b158a3e1 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.6.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 15 September 2012. +This document describes ngx_lua [v0.6.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 September 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 55b5206910..a292b92247 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.6.5] released on 15 September 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.6] released on 20 September 2012. = Synopsis = From c0ac1197848f22fa7b542d1a1de57f32808c57ac Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 12:54:12 -0700 Subject: [PATCH 0063/2239] added (passing) tests for nested user threads. --- t/093-uthread.t | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/t/093-uthread.t b/t/093-uthread.t index 7d673a34d1..925d6e1d99 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -700,3 +700,86 @@ g: after capture: hello bah --- no_error_log [error] + + +=== TEST 14: nested user threads +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.create(f) + ngx.say("after f") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +create user thread 3 in 2 +delete thread 3 +delete thread 1 +delete thread 2 + +--- response_body +before f +before g +hello in g() +after f +after g +--- no_error_log +[error] + + + +=== TEST 15: nested user threads (with I/O) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.sleep(0.1) + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.create(f) + ngx.say("after f") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +create user thread 3 in 2 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before f +before g +after f +after g +hello in g() +--- no_error_log +[error] + From 4282176462ce4b7a0c412f2393efefe7a396f29b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 13:05:06 -0700 Subject: [PATCH 0064/2239] added (passing) tests for the "coroutine status" of user threads. --- t/093-uthread.t | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/t/093-uthread.t b/t/093-uthread.t index 925d6e1d99..e82fef07e6 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -783,3 +783,97 @@ hello in g() --- no_error_log [error] + + +=== TEST 16: coroutine status of a running user thread +--- config + location /lua { + content_by_lua ' + local co + function f() + co = coroutine.running() + ngx.sleep(0.1) + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +status: running +--- no_error_log +[error] + + + +=== TEST 17: coroutine status of a dead user thread +--- config + location /lua { + content_by_lua ' + local co + function f() + co = coroutine.running() + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +status: dead +--- no_error_log +[error] + + + +=== TEST 18: coroutine status of a "normal" user thread +--- config + location /lua { + content_by_lua ' + local co + function f() + co = coroutine.running() + local co2 = coroutine.create(g) + coroutine.resume(co2) + end + + function g() + ngx.sleep(0.1) + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +status: normal +--- no_error_log +[error] + From 3b0d04b9560408cd395f51c23ca5d8da18d4537f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 15:05:03 -0700 Subject: [PATCH 0065/2239] added a (passing) test for creating user threads in a user coroutine. also tracked user coroutine creation in the test cases for user threads. --- t/093-uthread.t | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/t/093-uthread.t b/t/093-uthread.t index e82fef07e6..b981fd35a7 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -42,6 +42,12 @@ M(http-lua-thread-delete) { printf("delete thread %x\n", t) } +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + _EOC_ our $StapScript = <<'_EOC_'; @@ -185,6 +191,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -224,8 +231,10 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 +create 3 in 1 create user thread 3 in 1 delete thread 3 delete thread 1 @@ -262,6 +271,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -306,7 +316,9 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 +create 3 in 1 create user thread 3 in 1 delete thread 1 delete thread 3 @@ -347,6 +359,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -379,6 +392,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -414,6 +428,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -446,6 +461,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -474,6 +490,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -514,6 +531,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -563,6 +581,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -614,6 +633,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -681,7 +701,9 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 +create 3 in 1 create user thread 3 in 1 delete thread 2 delete thread 1 @@ -726,7 +748,9 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 +create 3 in 2 create user thread 3 in 2 delete thread 3 delete thread 1 @@ -768,7 +792,9 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 +create 3 in 2 create user thread 3 in 2 delete thread 1 delete thread 2 @@ -804,6 +830,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 1 delete thread 2 @@ -833,6 +860,7 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 delete thread 2 delete thread 1 @@ -868,7 +896,9 @@ GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out +create 2 in 1 create user thread 2 in 1 +create 3 in 2 delete thread 1 delete thread 2 @@ -877,3 +907,45 @@ status: normal --- no_error_log [error] + + +=== TEST 19: creating user threads in a user coroutine +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + local co = coroutine.create(f) + coroutine.resume(co) + ngx.say("after f") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 3 +delete thread 1 + +--- response_body +before f +before g +hello in g() +after g +after f +--- no_error_log +[error] + From 518c94eaad30b0af6f168da2d6b8db8d8c80ba7f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 16:17:45 -0700 Subject: [PATCH 0066/2239] feature: added support for manual time-slicing between lightweight threads via the coroutine.yield() API. --- dtrace/ngx_lua_provider.d | 6 +- src/ngx_http_lua_contentby.c | 3 + src/ngx_http_lua_probe.h | 10 ++- src/ngx_http_lua_util.c | 25 +++++-- t/093-uthread.t | 128 ++++++++++++++++++++++++++++++++++- 5 files changed, 160 insertions(+), 12 deletions(-) diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index 784b829f78..b20a8ba213 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -38,8 +38,12 @@ provider nginx_lua { probe http__lua__user__thread__create(ngx_http_request_t *r, void *creator, void *newthread); + /* lua_State *thread, ngx_http_lua_ctx_t *ctx */ + probe http__lua__thread__delete(ngx_http_request_t *r, void *thread, void *ctx); + /* lua_State *thread */ - probe http__lua__thread__delete(ngx_http_request_t *r, void *thread); + probe http__lua__run__posted__thread(ngx_http_request_t *r, void *thread, + int status); }; diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index e7fca54ced..57d5c2a731 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -305,6 +305,9 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, ctx->posted_threads = pt->next; + ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co, + (int) pt->co_ctx->co_status); + if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) { continue; } diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index 7f2176d38b..aaf31d37db 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -50,8 +50,11 @@ #define ngx_http_lua_probe_user_thread_create(r, creator, newthread) \ NGINX_LUA_HTTP_LUA_USER_THREAD_CREATE(r, creator, newthread) -#define ngx_http_lua_probe_thread_delete(r, thread) \ - NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread) +#define ngx_http_lua_probe_thread_delete(r, thread, ctx) \ + NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread, ctx) + +#define ngx_http_lua_probe_run_posted_thread(r, thread, status) \ + NGINX_LUA_HTTP_LUA_RUN_POSTED_THREAD(r, thread, status) #else /* !(NGX_DTRACE) */ @@ -66,7 +69,8 @@ #define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len) #define ngx_http_lua_probe_user_thread_create(r, creator, newthread) -#define ngx_http_lua_probe_thread_delete(r, thread) +#define ngx_http_lua_probe_thread_delete(r, thread, ctx) +#define ngx_http_lua_probe_run_posted_thread(r, thread, status) #endif diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index cb1b74f17a..f36decb221 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -290,7 +290,7 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - ngx_http_lua_probe_thread_delete(r, coctx->co); + ngx_http_lua_probe_thread_delete(r, coctx->co, ctx); luaL_unref(L, -1, coctx->co_ref); coctx->co_ref = LUA_NOREF; @@ -324,7 +324,7 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, ref = cc[i].co_ref; if (ref != LUA_NOREF) { - ngx_http_lua_probe_thread_delete(r, cc[i].co); + ngx_http_lua_probe_thread_delete(r, cc[i].co, ctx); luaL_unref(L, -1, ref); cc[i].co_ref = LUA_NOREF; @@ -349,7 +349,7 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, inited = 1; } - ngx_http_lua_probe_thread_delete(r, entry_coctx->co); + ngx_http_lua_probe_thread_delete(r, entry_coctx->co, ctx); luaL_unref(L, -1, entry_coctx->co_ref); entry_coctx->co_ref = LUA_NOREF; @@ -996,12 +996,22 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - if (ctx->cur_co_ctx->co_ref != LUA_NOREF) { - /* threads yielded will be resumed immediately */ - + if (ngx_http_lua_is_thread(ctx)) { ngx_http_lua_probe_thread_yield(r, ctx->cur_co_ctx->co); lua_settop(ctx->cur_co_ctx->co, 0); + + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + + if (ctx->posted_threads) { + ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx); + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } + + /* no pending threads, so resume the thread + * immediately */ + nrets = 0; continue; } @@ -2611,6 +2621,9 @@ ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, ctx->posted_threads = pt->next; + ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co, + (int) pt->co_ctx->co_status); + if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) { continue; } diff --git a/t/093-uthread.t b/t/093-uthread.t index b981fd35a7..f56b37a413 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -54,6 +54,7 @@ our $StapScript = <<'_EOC_'; global ids, cur global timers global in_req = 0 +global co_status function gen_id(k) { if (ids[k]) return ids[k] @@ -66,6 +67,10 @@ F(ngx_http_init_request) { if (in_req == 1) { delete ids cur = 0 + co_status[0] = "running" + co_status[1] = "suspended" + co_status[2] = "normal" + co_status[3] = "dead" } } @@ -73,6 +78,11 @@ F(ngx_http_free_request) { in_req-- } +F(ngx_http_lua_post_thread) { + id = gen_id($coctx->co) + printf("post thread %d\n", id) +} + F(ngx_http_lua_co_cleanup) { id = gen_id(@cast($data, "ngx_http_lua_co_ctx_t")->co) printf("co cleanup called for thread %d\n", id) @@ -118,7 +128,14 @@ M(http-lua-user-thread-create) { M(http-lua-thread-delete) { t = gen_id($arg2) - printf("delete thread %x\n", t) + uthreads = @cast($arg3, "ngx_http_lua_ctx_t")->uthreads + printf("delete thread %x (uthreads %d)\n", t, uthreads) + #print_ubacktrace() +} + +M(http-lua-run-posted-thread) { + t = gen_id($arg2) + printf("run posted thread %d (status %s)\n", t, co_status[$arg3]) } M(http-lua-user-coroutine-resume) { @@ -128,7 +145,8 @@ M(http-lua-user-coroutine-resume) { } M(http-lua-thread-yield) { - println("thread yield") + t = gen_id($arg2) + printf("thread %d yield\n", t) } /* @@ -949,3 +967,109 @@ after f --- no_error_log [error] + + +=== TEST 20: manual time slicing between a user thread and the entry thread +--- config + location /lua { + content_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + ngx.say("1") + ngx.thread.create(f) + ngx.say("2") + yield(self) + ngx.say("3") + yield(self) + ngx.say("4") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +0 +1 +f 1 +2 +f 2 +3 +f 3 +4 +--- no_error_log +[error] + + + +=== TEST 21: manual time slicing between two user threads +--- config + location /lua { + content_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + function g() + local self = coroutine.running() + ngx.say("g 1") + yield(self) + ngx.say("g 2") + yield(self) + ngx.say("g 3") + end + + ngx.thread.create(f) + ngx.thread.create(g) + ngx.say("done") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +f 1 +g 1 +f 2 +done +g 2 +f 3 +g 3 +--- no_error_log +[error] + From 985c4a5e941d68f074865b4340a6ed204281ac11 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 18:18:03 -0700 Subject: [PATCH 0067/2239] added (passing) tests for ngx.flush(true) + ngx.thread. --- t/093-uthread.t | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/t/093-uthread.t b/t/093-uthread.t index f56b37a413..1181d0064f 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -1073,3 +1073,83 @@ g 3 --- no_error_log [error] + + +=== TEST 22: entry thread and a user thread flushing at the same time +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + coroutine.yield(coroutine.running) + ngx.flush(true) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.flush(true) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 23: two user threads flushing at the same time +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello from f") + ngx.flush(true) + end + + function g() + ngx.say("hello from g") + ngx.flush(true) + end + + ngx.thread.create(f) + ngx.thread.create(g) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3|create 2 in 1 +create user thread 2 in 1 +delete thread 2 +create 3 in 1 +create user thread 3 in 1 +delete thread 3 +delete thread 1)$ + +--- response_body +hello from f +hello from g +--- no_error_log +[error] + From b4e6bf1742ddd20631c027078553eb7946f05dce Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 19:09:05 -0700 Subject: [PATCH 0068/2239] added (passing) tests for UPD/TCP cosockets + ngx.thread. --- t/093-uthread.t | 98 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/t/093-uthread.t b/t/093-uthread.t index 1181d0064f..7611a83b45 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -5,9 +5,10 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4); +plan tests => repeat_each() * (blocks() * 4 + 1); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; our $GCScript = <<'_EOC_'; global ids, cur @@ -1153,3 +1154,98 @@ hello from g --- no_error_log [error] + + +=== TEST 24: user threads + ngx.socket.tcp +--- config + location /lua { + content_by_lua ' + function f() + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + local bytes, err = sock:send("flush_all\\r\\n") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before +after +received: OK +--- no_error_log +[error] + + + +=== TEST 25: user threads + ngx.socket.udp +--- config + location /lua { + content_by_lua ' + function f() + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("127.0.0.1", 12345) + local bytes, err = sock:send("blah") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- udp_listen: 12345 +--- udp_query: blah +--- udp_reply: hello udp +--- response_body +before +after +received: hello udp +--- no_error_log +[error] + From c1f40cd904690b30eb7fea17ecb501ab8dd3f2ab Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 19:23:34 -0700 Subject: [PATCH 0069/2239] added (passing) tests for ngx.req.socket() + ngx.thread and ngx.req.read_body() + ngx.thread. --- t/093-uthread.t | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/t/093-uthread.t b/t/093-uthread.t index 7611a83b45..ad7a9138ce 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -1249,3 +1249,90 @@ received: hello udp --- no_error_log [error] + + +=== TEST 26: simple user thread with ngx.req.read_body() +--- config + location /lua { + content_by_lua ' + function f() + ngx.req.read_body() + local body = ngx.req.get_body_data() + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2)$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + + + +=== TEST 27: simple user thread with ngx.req.socket() +--- config + location /lua { + content_by_lua ' + function f() + local sock = ngx.req.socket() + local body, err = sock:receive(11) + if not body then + ngx.say("failed to read body: ", err) + return + end + + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2)$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + From 889a24afdfae8a2e36cbae9688cdcbc2eefc1f2d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Sep 2012 23:20:47 -0700 Subject: [PATCH 0070/2239] refactor: ensure that we always bypass ngx_http_postpone_filter_module when we generating downstream outputs. also removed all the legacy code handling postponed outputs. --- src/ngx_http_lua_capturefilter.c | 2 +- src/ngx_http_lua_subrequest.c | 26 ------------ src/ngx_http_lua_util.c | 70 ++++++++++++++++++++++++-------- src/ngx_http_lua_util.h | 2 - 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index a98a1b60ff..cb866b465b 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -149,6 +149,6 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_lua_discard_bufs(r->pool, in); - return ngx_http_lua_flush_postponed_outputs(r); + return NGX_OK; } diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 2fb5f55378..23cea2c6ba 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1274,9 +1274,6 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, ngx_connection_t *c; ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; -#if 0 - ngx_http_postponed_request_t *pr, *p; -#endif r->main->subrequests--; @@ -1360,33 +1357,10 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->read_event_handler = ngx_http_request_empty_handler; sr->write_event_handler = ngx_http_handler; - if (c->data == r && r->postponed == NULL) { - c->data = sr; - } - sr->variables = r->variables; sr->log_handler = r->log_handler; -#if 0 - pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); - if (pr == NULL) { - return NGX_ERROR; - } - - pr->request = sr; - pr->out = NULL; - pr->next = NULL; - - if (r->postponed) { - for (p = r->postponed; p->next; p = p->next) { /* void */ } - p->next = pr; - - } else { - r->postponed = pr; - } -#endif - sr->internal = 1; sr->discard_body = r->discard_body; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1acb8b188c..448c1af349 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -68,6 +68,10 @@ static void ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L); static void ngx_http_lua_inject_arg_api(lua_State *L); static int ngx_http_lua_param_get(lua_State *L); static int ngx_http_lua_param_set(lua_State *L); +static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r, + ngx_chain_t *in); +static ngx_int_t ngx_http_lua_send_special(ngx_http_request_t *r, + ngx_uint_t flags); #ifndef LUA_PATH_SEP @@ -417,7 +421,8 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, } if (ctx->out) { - rc = ngx_http_output_filter(r, ctx->out); + + rc = ngx_http_lua_output_filter(r, ctx->out); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; @@ -442,7 +447,8 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua sending last buf of the response body"); - rc = ngx_http_send_special(r, NGX_HTTP_LAST); + rc = ngx_http_lua_send_special(r, NGX_HTTP_LAST); + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } @@ -465,6 +471,50 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, return NGX_OK; } + return ngx_http_lua_output_filter(r, in); +} + + +static ngx_int_t +ngx_http_lua_send_special(ngx_http_request_t *r, ngx_uint_t flags) +{ + ngx_int_t rc; + ngx_http_request_t *ar; /* active request */ + + ar = r->connection->data; + + if (ar != r) { + + /* bypass ngx_http_postpone_filter_module */ + + r->connection->data = r; + rc = ngx_http_send_special(r, flags); + r->connection->data = ar; + return rc; + } + + return ngx_http_send_special(r, flags); +} + + +static ngx_int_t +ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_http_request_t *ar; /* active request */ + + ar = r->connection->data; + + if (ar != r) { + + /* bypass ngx_http_postpone_filter_module */ + + r->connection->data = r; + rc = ngx_http_output_filter(r, in); + r->connection->data = ar; + return rc; + } + return ngx_http_output_filter(r, in); } @@ -1217,7 +1267,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) "lua wev handler flushing output: buffered 0x%uxd", c->buffered); - rc = ngx_http_output_filter(r, NULL); + rc = ngx_http_lua_output_filter(r, NULL); if (rc == NGX_ERROR || rc > NGX_OK) { if (ctx->entered_content_phase) { @@ -1362,20 +1412,6 @@ ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, int buf_len) } -ngx_int_t -ngx_http_lua_flush_postponed_outputs(ngx_http_request_t *r) -{ - if (r == r->connection->data && r->postponed) { - /* notify the downstream postpone filter to flush the postponed - * outputs of the current request */ - return ngx_http_lua_next_body_filter(r, NULL); - } - - /* do nothing */ - return NGX_OK; -} - - void ngx_http_lua_set_multi_value_table(lua_State *L, int index) { diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 434d03300f..7a35a25126 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -93,8 +93,6 @@ ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r); u_char * ngx_http_lua_digest_hex(u_char *dest, const u_char *buf, int buf_len); -ngx_int_t ngx_http_lua_flush_postponed_outputs(ngx_http_request_t *r); - void ngx_http_lua_set_multi_value_table(lua_State *L, int index); void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, From 07b9b3b6ca5e89f7ba36fc6936c8efa6b2706546 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 11:34:31 -0700 Subject: [PATCH 0071/2239] bugfix: when the entry coroutine was yielded by coroutine.yield() then after it was resumed automatically its status would still be "suspended". --- src/ngx_http_lua_util.c | 3 +++ t/091-coroutine.t | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 448c1af349..1f2deb2efd 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -987,10 +987,13 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua coroutine: yield"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; + if (ctx->cur_co_ctx->co == ctx->entry_co_ctx.co) { /* entry coroutine yielded will be resumed * immediately */ + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; + ngx_http_lua_probe_entry_coroutine_yield(r, ctx->cur_co_ctx->co); diff --git a/t/091-coroutine.t b/t/091-coroutine.t index 0c907daf4c..10bf571c73 100644 --- a/t/091-coroutine.t +++ b/t/091-coroutine.t @@ -903,3 +903,23 @@ parent: status: running --- error_log lua coroutine: runtime error: [string "content_by_lua"]:4: bad + + +=== TEST 22: entry coroutine is yielded by hand and still gets the right status +--- config + location /t { + content_by_lua ' + local co = coroutine.running() + ngx.say("status: ", coroutine.status(co)) + coroutine.yield(co) + ngx.say("status: ", coroutine.status(co)) + '; + } +--- request +GET /t +--- response_body +status: running +status: running +--- no_error_log +[error] + From b63c3156ae0f05e0edb175c27eee4faee1ffea77 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 12:39:15 -0700 Subject: [PATCH 0072/2239] refactor: now we introduce an explicit is_uthread flag for each user thread. --- src/ngx_http_lua_common.h | 3 +++ src/ngx_http_lua_uthread.c | 1 + src/ngx_http_lua_uthread.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 2f9286460f..9dd4db2a2e 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -249,6 +249,9 @@ struct ngx_http_lua_co_ctx_s { unsigned flushing:1; /* indicates whether the current coroutine is waiting for ngx.flush(true) */ + + unsigned is_uthread:1; /* whether the current coroutine is + a user thread */ }; diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 338395ab4b..97cca8661f 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -43,6 +43,7 @@ ngx_http_lua_uthread_create(lua_State *L) coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); + coctx->is_uthread = 1; ctx->uthreads++; coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; diff --git a/src/ngx_http_lua_uthread.h b/src/ngx_http_lua_uthread.h index 1d7cc6aacd..9637e465fa 100644 --- a/src/ngx_http_lua_uthread.h +++ b/src/ngx_http_lua_uthread.h @@ -6,7 +6,7 @@ #define ngx_http_lua_is_thread(ctx) \ - ((ctx)->cur_co_ctx->co_ref != LUA_NOREF) + ((ctx)->cur_co_ctx->is_uthread || (ctx)->cur_co_ctx == &(ctx)->entry_co_ctx) #define ngx_http_lua_is_entry_thread(ctx) \ From 5e6a5b3e74eae6a98d950622d02d81e9b74adf4f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 17:26:17 -0700 Subject: [PATCH 0073/2239] bugfix: ngx.thread abortion did not clean up the ngx.sleep timer in time. also refactored the uthread tests a bit. --- src/ngx_http_lua_common.h | 2 +- src/ngx_http_lua_sleep.c | 23 +-- src/ngx_http_lua_util.c | 51 +++++- t/093-uthread.t | 357 +++----------------------------------- t/094-uthread-exit | 287 ++++++++++++++++++++++++++++++ t/095-uthread-exec.t | 256 +++++++++++++++++++++++++++ t/StapThread.pm | 184 ++++++++++++++++++++ 7 files changed, 805 insertions(+), 355 deletions(-) create mode 100644 t/094-uthread-exit create mode 100644 t/095-uthread-exec.t create mode 100644 t/StapThread.pm diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 9dd4db2a2e..31d1a93f43 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -221,7 +221,7 @@ struct ngx_http_lua_co_ctx_s { lua_State *co; ngx_http_lua_co_ctx_t *parent_co_ctx; - ngx_http_cleanup_pt *cleanup; + ngx_http_cleanup_pt cleanup; unsigned nsubreqs; /* number of subrequests of the * current request */ diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 62e44be883..6dee4c649f 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -10,7 +10,7 @@ static int ngx_http_lua_ngx_sleep(lua_State *L); static void ngx_http_lua_sleep_handler(ngx_event_t *ev); -static void ngx_http_lua_co_cleanup(void *data); +static void ngx_http_lua_sleep_cleanup(void *data); static ngx_int_t ngx_http_lua_sleep_resume(ngx_http_request_t *r); @@ -22,7 +22,6 @@ ngx_http_lua_ngx_sleep(lua_State *L) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; - ngx_http_cleanup_t *cln; n = lua_gettop(L); if (n != 1) { @@ -67,16 +66,7 @@ ngx_http_lua_ngx_sleep(lua_State *L) ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); - if (coctx->cleanup == NULL) { - cln = ngx_http_cleanup_add(r, 0); - if (cln == NULL) { - return luaL_error(L, "out of memory"); - } - - cln->handler = ngx_http_lua_co_cleanup; - cln->data = coctx; - coctx->cleanup = &cln->handler; - } + coctx->cleanup = ngx_http_lua_sleep_cleanup; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); @@ -116,6 +106,8 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) return; } + coctx->cleanup = NULL; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args); @@ -149,15 +141,10 @@ ngx_http_lua_inject_sleep_api(lua_State *L) static void -ngx_http_lua_co_cleanup(void *data) +ngx_http_lua_sleep_cleanup(void *data) { ngx_http_lua_co_ctx_t *coctx = data; - if (coctx->cleanup) { - *coctx->cleanup = NULL; - coctx->cleanup = NULL; - } - if (coctx->sleep.timer_set) { dd("cleanup: deleting timer for ngx.sleep"); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index ad72a07b69..067cdfc431 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -75,6 +75,8 @@ static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r, ngx_chain_t *in); static ngx_int_t ngx_http_lua_send_special(ngx_http_request_t *r, ngx_uint_t flags); +static void ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx); #ifndef LUA_PATH_SEP @@ -902,8 +904,6 @@ ngx_http_lua_request_cleanup(void *data) } } - /* threads not cleaned up yet */ - ngx_http_lua_del_all_threads(r, L, ctx); } @@ -1860,7 +1860,8 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, "lua thread initiated internal redirect to %V", &ctx->exec_uri); - ngx_http_lua_del_all_threads(r, L, ctx); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); if (ctx->exec_uri.data[0] == '@') { @@ -1943,7 +1944,8 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, } #endif - ngx_http_lua_del_all_threads(r, L, ctx); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); if ((ctx->exit_code == NGX_OK @@ -2198,8 +2200,8 @@ 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); - ngx_http_lua_del_all_threads(r, L, ctx); - + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); return NGX_OK; @@ -2712,3 +2714,40 @@ ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, return NGX_OK; } + +static void +ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) +{ + ngx_http_lua_co_ctx_t *cc, *coctx; + ngx_uint_t i; + + if (ctx->uthreads == 0) { + if (ngx_http_lua_is_entry_thread(ctx)) { + return; + } + + /* the current thread is not the entry thread */ + + if (ctx->entry_co_ctx.co_status == NGX_HTTP_LUA_CO_DEAD) { + return; + } + } + + cc = ctx->user_co_ctx->elts; + + for (i = 0; i < ctx->user_co_ctx->nelts; i++) { + coctx = &cc[i]; + if (coctx->cleanup) { + coctx->cleanup(coctx); + coctx->cleanup = NULL; + coctx->co_status = NGX_HTTP_LUA_CO_DEAD; + /* TODO we could also free the user thread here */ + } + } + + coctx = &ctx->entry_co_ctx; + if (coctx->cleanup) { + coctx->cleanup(coctx); + } +} + diff --git a/t/093-uthread.t b/t/093-uthread.t index ad7a9138ce..4b809ffe27 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -2,6 +2,10 @@ use lib 'lib'; use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; repeat_each(2); @@ -10,182 +14,6 @@ plan tests => repeat_each() * (blocks() * 4 + 1); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; -our $GCScript = <<'_EOC_'; -global ids, cur -global in_req = 0 - -function gen_id(k) { - if (ids[k]) return ids[k] - ids[k] = ++cur - return cur -} - -F(ngx_http_init_request) { - in_req++ - if (in_req == 1) { - delete ids - cur = 0 - } -} - -F(ngx_http_free_request) { - in_req-- -} - -M(http-lua-user-thread-create) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("create user thread %x in %x\n", c, p) -} - -M(http-lua-thread-delete) { - t = gen_id($arg2) - printf("delete thread %x\n", t) -} - -M(http-lua-user-coroutine-create) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("create %x in %x\n", c, p) -} - -_EOC_ - -our $StapScript = <<'_EOC_'; -global ids, cur -global timers -global in_req = 0 -global co_status - -function gen_id(k) { - if (ids[k]) return ids[k] - ids[k] = ++cur - return cur -} - -F(ngx_http_init_request) { - in_req++ - if (in_req == 1) { - delete ids - cur = 0 - co_status[0] = "running" - co_status[1] = "suspended" - co_status[2] = "normal" - co_status[3] = "dead" - } -} - -F(ngx_http_free_request) { - in_req-- -} - -F(ngx_http_lua_post_thread) { - id = gen_id($coctx->co) - printf("post thread %d\n", id) -} - -F(ngx_http_lua_co_cleanup) { - id = gen_id(@cast($data, "ngx_http_lua_co_ctx_t")->co) - printf("co cleanup called for thread %d\n", id) -} - -M(timer-add) { - timers[$arg1] = $arg2 - printf("add timer %d\n", $arg2) -} - -M(timer-del) { - printf("delete timer %d\n", timers[$arg1]) -} - -M(timer-expire) { - printf("expire timer %d\n", timers[$arg1]) -} - -F(ngx_http_lua_sleep_handler) { - printf("sleep handler called\n") -} - -F(ngx_http_lua_run_thread) { - id = gen_id($ctx->cur_co_ctx->co) - printf("run thread %d\n", id) - #if (id == 1) { - #print_ubacktrace() - #} -} - -/* -probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { - id = gen_id($L) - printf("lua resume %d\n", id) -} -*/ - -M(http-lua-user-thread-create) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("create uthread %x in %x\n", c, p) -} - -M(http-lua-thread-delete) { - t = gen_id($arg2) - uthreads = @cast($arg3, "ngx_http_lua_ctx_t")->uthreads - printf("delete thread %x (uthreads %d)\n", t, uthreads) - #print_ubacktrace() -} - -M(http-lua-run-posted-thread) { - t = gen_id($arg2) - printf("run posted thread %d (status %s)\n", t, co_status[$arg3]) -} - -M(http-lua-user-coroutine-resume) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("resume %x in %x\n", c, p) -} - -M(http-lua-thread-yield) { - t = gen_id($arg2) - printf("thread %d yield\n", t) -} - -/* -F(ngx_http_lua_coroutine_yield) { - printf("yield %x\n", gen_id($L)) -} -*/ - -M(http-lua-user-coroutine-yield) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("yield %x in %x\n", c, p) -} - -F(ngx_http_lua_atpanic) { - printf("lua atpanic(%d):", gen_id($L)) - print_ubacktrace(); -} - -F(ngx_http_lua_run_posted_threads) { - printf("run posted threads\n") -} - -F(ngx_http_finalize_request) { - printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); -} - -M(http-lua-user-coroutine-create) { - p = gen_id($arg2) - c = gen_id($arg3) - printf("create %x in %x\n", c, p) -} - -F(ngx_http_lua_ngx_exec) { println("exec") } - -F(ngx_http_lua_ngx_exit) { println("exit") } -_EOC_ - #no_shuffle(); no_long_string(); run_tests(); @@ -357,142 +185,7 @@ delete thread 2 -=== TEST 5: exit in user thread (entry still pending) ---- config - location /lua { - content_by_lua ' - function f() - ngx.say("hello in thread") - ngx.exit(0) - end - - ngx.say("before") - ngx.thread.create(f) - ngx.say("after") - ngx.sleep(1) - ngx.say("end") - '; - } ---- request -GET /lua ---- stap2 eval: $::StapScript ---- stap eval: $::GCScript ---- stap_out -create 2 in 1 -create user thread 2 in 1 -delete thread 2 -delete thread 1 - ---- response_body -before -hello in thread ---- no_error_log -[error] - - - -=== TEST 6: exit in user thread (entry already quits) ---- config - location /lua { - content_by_lua ' - function f() - ngx.sleep(0.1) - ngx.say("exiting the user thread") - ngx.exit(0) - end - - ngx.say("before") - ngx.thread.create(f) - ngx.say("after") - '; - } ---- request -GET /lua ---- stap2 eval: $::StapScript ---- stap eval: $::GCScript ---- stap_out -create 2 in 1 -create user thread 2 in 1 -delete thread 1 -delete thread 2 - ---- response_body -before -after -exiting the user thread ---- no_error_log -[error] - - - -=== TEST 7: exec in user thread (entry still pending) ---- config - location /lua { - content_by_lua ' - function f() - ngx.exec("/foo") - end - - ngx.thread.create(f) - ngx.sleep(1) - ngx.say("hello") - '; - } - - location /foo { - echo i am foo; - } ---- request -GET /lua ---- stap2 eval: $::StapScript ---- stap eval: $::GCScript ---- stap_out -create 2 in 1 -create user thread 2 in 1 -delete thread 2 -delete thread 1 - ---- response_body -i am foo ---- no_error_log -[error] - - - -=== TEST 8: exec in user thread (entry already quits) ---- config - location /lua { - content_by_lua ' - function f() - ngx.sleep(0.1) - ngx.exec("/foo") - end - - ngx.thread.create(f) - '; - } - - location /foo { - echo i am foo; - } ---- request -GET /lua ---- stap2 eval: $::StapScript ---- stap eval: $::GCScript ---- stap_out -create 2 in 1 -create user thread 2 in 1 -delete thread 1 -delete thread 2 - ---- response_body -i am foo ---- no_error_log -[error] - - - -=== TEST 9: error in user thread +=== TEST 5: error in user thread --- config location /lua { content_by_lua ' @@ -521,7 +214,7 @@ lua thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call -=== TEST 10: simple user threads doing a single subrequest (entry quits early) +=== TEST 6: simple user threads doing a single subrequest (entry quits early) --- config location /lua { content_by_lua ' @@ -565,7 +258,7 @@ after capture: hello world -=== TEST 11: simple user threads doing a single subrequest (entry also does a subrequest and quits early) +=== TEST 7: simple user threads doing a single subrequest (entry also does a subrequest and quits early) --- config location /lua { content_by_lua ' @@ -616,7 +309,7 @@ after capture: hello foo -=== TEST 12: simple user threads doing a single subrequest (entry also does a subrequest and quits late) +=== TEST 8: simple user threads doing a single subrequest (entry also does a subrequest and quits late) --- config location /lua { content_by_lua ' @@ -668,7 +361,7 @@ capture: hello bar -=== TEST 13: two simple user threads doing single subrequests (entry also does a subrequest and quits between) +=== TEST 9: two simple user threads doing single subrequests (entry also does a subrequest and quits between) --- config location /lua { content_by_lua ' @@ -743,7 +436,7 @@ g: after capture: hello bah -=== TEST 14: nested user threads +=== TEST 10: nested user threads --- config location /lua { content_by_lua ' @@ -786,7 +479,7 @@ after g -=== TEST 15: nested user threads (with I/O) +=== TEST 11: nested user threads (with I/O) --- config location /lua { content_by_lua ' @@ -830,7 +523,7 @@ hello in g() -=== TEST 16: coroutine status of a running user thread +=== TEST 12: coroutine status of a running user thread --- config location /lua { content_by_lua ' @@ -861,7 +554,7 @@ status: running -=== TEST 17: coroutine status of a dead user thread +=== TEST 13: coroutine status of a dead user thread --- config location /lua { content_by_lua ' @@ -891,7 +584,7 @@ status: dead -=== TEST 18: coroutine status of a "normal" user thread +=== TEST 14: coroutine status of a "normal" user thread --- config location /lua { content_by_lua ' @@ -928,7 +621,7 @@ status: normal -=== TEST 19: creating user threads in a user coroutine +=== TEST 15: creating user threads in a user coroutine --- config location /lua { content_by_lua ' @@ -970,7 +663,7 @@ after f -=== TEST 20: manual time slicing between a user thread and the entry thread +=== TEST 16: manual time slicing between a user thread and the entry thread --- config location /lua { content_by_lua ' @@ -1021,7 +714,7 @@ f 3 -=== TEST 21: manual time slicing between two user threads +=== TEST 17: manual time slicing between two user threads --- config location /lua { content_by_lua ' @@ -1076,7 +769,7 @@ g 3 -=== TEST 22: entry thread and a user thread flushing at the same time +=== TEST 18: entry thread and a user thread flushing at the same time --- config location /lua { content_by_lua ' @@ -1111,7 +804,7 @@ after -=== TEST 23: two user threads flushing at the same time +=== TEST 19: two user threads flushing at the same time --- config location /lua { content_by_lua ' @@ -1156,13 +849,17 @@ hello from g -=== TEST 24: user threads + ngx.socket.tcp +=== TEST 20: user threads + ngx.socket.tcp --- config location /lua { content_by_lua ' function f() 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 local bytes, err = sock:send("flush_all\\r\\n") if not bytes then ngx.say("failed to send query: ", err) @@ -1202,7 +899,7 @@ received: OK -=== TEST 25: user threads + ngx.socket.udp +=== TEST 21: user threads + ngx.socket.udp --- config location /lua { content_by_lua ' @@ -1251,7 +948,7 @@ received: hello udp -=== TEST 26: simple user thread with ngx.req.read_body() +=== TEST 22: simple user thread with ngx.req.read_body() --- config location /lua { content_by_lua ' @@ -1292,7 +989,7 @@ body: hello world)$ -=== TEST 27: simple user thread with ngx.req.socket() +=== TEST 23: simple user thread with ngx.req.socket() --- config location /lua { content_by_lua ' diff --git a/t/094-uthread-exit b/t/094-uthread-exit new file mode 100644 index 0000000000..a2ab22aa6e --- /dev/null +++ b/t/094-uthread-exit @@ -0,0 +1,287 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 5: exit in user thread (entry thread is still pending to run) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +M(timer-add) { + if ($arg2 == 1000) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 1000) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 1000) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +before +hello in thread +--- no_error_log +[error] + + + +=== TEST 6: exit in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 7: exit in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f") + ngx.exit(0) + end + + function g() + ngx.sleep(1) + ngx.say("g") + end + + ngx.thread.create(f) + ngx.thread.create(g) + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +free request + +--- response_body +end +f +--- no_error_log +[error] + + + +=== TEST 8: exit in user thread (entry already quits) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("exiting the user thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +before +after +exiting the user thread +--- no_error_log +[error] + diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t new file mode 100644 index 0000000000..432ea47b44 --- /dev/null +++ b/t/095-uthread-exec.t @@ -0,0 +1,256 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: exec in user thread (entry still pending) +--- config + location /lua { + content_by_lua ' + function f() + ngx.exec("/foo") + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("hello") + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 2: exec in user thread (entry already quits) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 3: exec in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + ngx.sleep(1) + '; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 4: exec in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + function g() + ngx.sleep(1) + end + + ngx.thread.create(f) + ngx.thread.create(g) + '; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +free request + +--- response_body +hello foo +--- no_error_log +[error] + diff --git a/t/StapThread.pm b/t/StapThread.pm new file mode 100644 index 0000000000..734b6561c7 --- /dev/null +++ b/t/StapThread.pm @@ -0,0 +1,184 @@ +package t::StapThread; + +use strict; +use warnings; + +our $GCScript = <<'_EOC_'; +global ids, cur +global in_req = 0 + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_init_request) { + in_req++ + if (in_req == 1) { + delete ids + cur = 0 + } +} + +F(ngx_http_free_request) { + in_req-- +} + +M(http-lua-user-thread-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create user thread %x in %x\n", c, p) +} + +M(http-lua-thread-delete) { + t = gen_id($arg2) + printf("delete thread %x\n", t) +} + +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + +_EOC_ + +our $StapScript = <<'_EOC_'; +global ids, cur +global timers +global in_req = 0 +global co_status + +function gen_id(k) { + if (ids[k]) return ids[k] + ids[k] = ++cur + return cur +} + +F(ngx_http_init_request) { + in_req++ + if (in_req == 1) { + delete ids + cur = 0 + co_status[0] = "running" + co_status[1] = "suspended" + co_status[2] = "normal" + co_status[3] = "dead" + } +} + +F(ngx_http_free_request) { + in_req-- +} + +F(ngx_http_lua_post_thread) { + id = gen_id($coctx->co) + printf("post thread %d\n", id) +} + +F(ngx_http_lua_co_cleanup) { + id = gen_id(@cast($data, "ngx_http_lua_co_ctx_t")->co) + printf("co cleanup called for thread %d\n", id) +} + +M(timer-add) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) +} + +M(timer-del) { + printf("delete timer %d\n", timers[$arg1]) + delete timers[$arg1] +} + +M(timer-expire) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] +} + +F(ngx_http_lua_sleep_handler) { + printf("sleep handler called\n") +} + +F(ngx_http_lua_run_thread) { + id = gen_id($ctx->cur_co_ctx->co) + printf("run thread %d\n", id) + #if (id == 1) { + #print_ubacktrace() + #} +} + +/* +probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { + id = gen_id($L) + printf("lua resume %d\n", id) +} +*/ + +M(http-lua-user-thread-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create uthread %x in %x\n", c, p) +} + +M(http-lua-thread-delete) { + t = gen_id($arg2) + uthreads = @cast($arg3, "ngx_http_lua_ctx_t")->uthreads + printf("delete thread %x (uthreads %d)\n", t, uthreads) + #print_ubacktrace() +} + +M(http-lua-run-posted-thread) { + t = gen_id($arg2) + printf("run posted thread %d (status %s)\n", t, co_status[$arg3]) +} + +M(http-lua-user-coroutine-resume) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("resume %x in %x\n", c, p) +} + +M(http-lua-thread-yield) { + t = gen_id($arg2) + printf("thread %d yield\n", t) +} + +/* +F(ngx_http_lua_coroutine_yield) { + printf("yield %x\n", gen_id($L)) +} +*/ + +M(http-lua-user-coroutine-yield) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("yield %x in %x\n", c, p) +} + +F(ngx_http_lua_atpanic) { + printf("lua atpanic(%d):", gen_id($L)) + print_ubacktrace(); +} + +F(ngx_http_lua_run_posted_threads) { + printf("run posted threads\n") +} + +F(ngx_http_finalize_request) { + printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); +} + +M(http-lua-user-coroutine-create) { + p = gen_id($arg2) + c = gen_id($arg3) + printf("create %x in %x\n", c, p) +} + +F(ngx_http_lua_ngx_exec) { println("exec") } + +F(ngx_http_lua_ngx_exit) { println("exit") } +_EOC_ + +1; From 3b5dc53b86f22b8decbd1073330443d396e019c4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 17:40:13 -0700 Subject: [PATCH 0074/2239] refactor: removed unnecessary code from the sleep handler for ngx.sleep(). --- src/ngx_http_lua_sleep.c | 13 ------------- t/023-rewrite/sleep.t | 7 +------ t/024-access/sleep.t | 7 +------ t/077-sleep.t | 8 ++------ 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index 401f8270ac..a9ee588d3e 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -108,22 +108,9 @@ ngx_http_lua_sleep_handler(ngx_event_t *ev) log_ctx = c->log->data; log_ctx->current_request = r; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "lua sleep handler: \"%V?%V\"", &r->uri, &r->args); - - if (!coctx->sleep.timedout) { - dd("reach lua sleep event handler without timeout!"); - return; - } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "lua sleep timer expired: \"%V?%V\"", &r->uri, &r->args); - if (coctx->sleep.timer_set) { - dd("deleting timer for lua_sleep"); - ngx_del_timer(&coctx->sleep); - } - ctx->cur_co_ctx = coctx; if (ctx->entered_content_phase) { diff --git a/t/023-rewrite/sleep.t b/t/023-rewrite/sleep.t index 5ee531b9dc..d178c8ab97 100644 --- a/t/023-rewrite/sleep.t +++ b/t/023-rewrite/sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 38; +plan tests => repeat_each() * 33; #no_diff(); #no_long_string(); @@ -36,7 +36,6 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-9]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" @@ -84,7 +83,6 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-9]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/sleep?" lua sleep timer expired: "/sleep?" --- no_error_log [error] @@ -131,7 +129,6 @@ GET /test ^0\.(?:8[5-9]\d*|9[0-9]\d*|9)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -160,7 +157,6 @@ GET /test blah --- error_log lua ready to sleep -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -191,7 +187,6 @@ blah hiya --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] diff --git a/t/024-access/sleep.t b/t/024-access/sleep.t index fff250d42b..8ff76e0686 100644 --- a/t/024-access/sleep.t +++ b/t/024-access/sleep.t @@ -10,7 +10,7 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 38; +plan tests => repeat_each() * 33; #no_diff(); #no_long_string(); @@ -36,7 +36,6 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-5]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" @@ -84,7 +83,6 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-9]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/sleep?" lua sleep timer expired: "/sleep?" --- no_error_log [error] @@ -131,7 +129,6 @@ GET /test ^0\.(?:8[5-9]\d*|9[0-9]\d*|9)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -160,7 +157,6 @@ GET /test blah --- error_log lua ready to sleep -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -191,7 +187,6 @@ blah hiya --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] diff --git a/t/077-sleep.t b/t/077-sleep.t index cb7bad12ab..a3b13bcea3 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() * 38; +plan tests => repeat_each() * 34; #no_diff(); #no_long_string(); @@ -35,7 +35,7 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-5]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" +lua sleep timer expired: "/test?" lua sleep timer expired: "/test?" @@ -81,7 +81,6 @@ GET /test ^0\.(?:4[5-9]\d*|5[0-9]\d*|5)$ --- error_log lua ready to sleep for -lua sleep handler: "/sleep?" lua sleep timer expired: "/sleep?" --- no_error_log [error] @@ -124,7 +123,6 @@ GET /test ^(?:0\.9\d*|1\.[0-2]\d*|1)$ --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -152,7 +150,6 @@ GET /test blah --- error_log lua ready to sleep -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] @@ -182,7 +179,6 @@ blah hiya --- error_log lua ready to sleep for -lua sleep handler: "/test?" lua sleep timer expired: "/test?" --- no_error_log [error] From 535edec6936d35574bede640cc6ccf4a2e9455e8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 17:50:45 -0700 Subject: [PATCH 0075/2239] renamed t/094-uthread-exit to t/094-uthread-exit.t. --- t/{094-uthread-exit => 094-uthread-exit.t} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename t/{094-uthread-exit => 094-uthread-exit.t} (100%) diff --git a/t/094-uthread-exit b/t/094-uthread-exit.t similarity index 100% rename from t/094-uthread-exit rename to t/094-uthread-exit.t From b771a2e400ef6ca95e1094c47247dba7de0376f8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Sep 2012 17:53:49 -0700 Subject: [PATCH 0076/2239] bugfix: when a coroutine aborts with errors, its status might not be updated to "dead". --- src/ngx_http_lua_util.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1f2deb2efd..e07effe314 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1094,27 +1094,22 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, continue; case LUA_ERRRUN: - ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "runtime error"; break; case LUA_ERRSYNTAX: - ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "syntax error"; break; case LUA_ERRMEM: - ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "memory allocation error"; break; case LUA_ERRERR: - ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "error handler error"; break; default: - ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; err = "unknown error"; break; } @@ -1127,6 +1122,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, msg = "unknown reason"; } + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co, ctx->cur_co_ctx); trace = lua_tostring(L, -1); From 5c22e1d4b0d3baf0d5ae008d7e9ea4d592cd28c3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 11:56:02 -0700 Subject: [PATCH 0077/2239] bugfix: ngx.thread abortion did not abort the nginx resolver for ngx.socket.tcp in time. --- src/ngx_http_lua_socket_tcp.c | 27 +++++++++ t/094-uthread-exit.t | 103 ++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 47dc0edb49..3e252721de 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -90,6 +90,7 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); static ngx_int_t ngx_http_lua_test_expect(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); enum { @@ -534,6 +535,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) saved_top = lua_gettop(L); + coctx->cleanup = ngx_http_lua_tcp_resolve_cleanup; + if (ngx_resolve_name(rctx) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket fail to run resolver immediately"); @@ -601,6 +604,9 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) } lctx->cur_co_ctx = u->co_ctx; + + u->co_ctx->cleanup = NULL; + L = lctx->cur_co_ctx->co; waiting = u->waiting; @@ -3860,3 +3866,24 @@ ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) return rc; } + +static void +ngx_http_lua_tcp_resolve_cleanup(void *data) +{ + ngx_resolver_ctx_t *rctx; + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_co_ctx_t *coctx = data; + + u = coctx->data; + if (u == NULL) { + return; + } + + rctx = u->resolved->ctx; + if (rctx == NULL) { + return; + } + + ngx_resolve_name_done(rctx); +} +# diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index a2ab22aa6e..d6743a3f36 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -20,7 +20,7 @@ run_tests(); __DATA__ -=== TEST 5: exit in user thread (entry thread is still pending to run) +=== TEST 1: exit in user thread (entry thread is still pending to run) --- config location /lua { content_by_lua ' @@ -82,7 +82,7 @@ hello in thread -=== TEST 6: exit in user thread (entry thread is still pending on ngx.sleep) +=== TEST 2: exit in user thread (entry thread is still pending on ngx.sleep) --- config location /lua { content_by_lua ' @@ -165,7 +165,7 @@ after -=== TEST 7: exit in a user thread (another user thread is still pending on ngx.sleep) +=== TEST 3: exit in a user thread (another user thread is still pending on ngx.sleep) --- config location /lua { content_by_lua ' @@ -253,7 +253,7 @@ f -=== TEST 8: exit in user thread (entry already quits) +=== TEST 4: exit in user thread (entry already quits) --- config location /lua { content_by_lua ' @@ -285,3 +285,98 @@ exiting the user thread --- no_error_log [error] + + +=== TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_resolve_cleanup) { + println("lua tcp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua tcp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 9fdf63663c5d8f885a78d1a13861d49331c80836 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 12:20:00 -0700 Subject: [PATCH 0078/2239] bugfix: the nginx resolver might not be destroyed in time when it was used by ngx.socket.tcp and ngx.socket.udp. --- src/ngx_http_lua_socket_tcp.c | 2 ++ src/ngx_http_lua_socket_udp.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 67fe0ad777..bcd9b97204 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -645,6 +645,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) #endif if (ur->naddrs == 0) { + ngx_resolve_name_done(ctx); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); @@ -665,6 +666,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in)); if (p == NULL) { + ngx_resolve_name_done(ctx); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index e31ea153ee..387018edb1 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -459,6 +459,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) #endif if (ur->naddrs == 0) { + ngx_resolve_name_done(ctx); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); @@ -479,6 +480,7 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in)); if (p == NULL) { + ngx_resolve_name_done(ctx); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); From ee02a8ca0736ae327b5c46c073813914c5353a9a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 12:27:11 -0700 Subject: [PATCH 0079/2239] updated .gitignore a bit. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 66bb089f26..a0bf9c3f76 100644 --- a/.gitignore +++ b/.gitignore @@ -153,4 +153,5 @@ src/uthread.[ch] lua Makefile tsubreq +tthread addr2line From c22c625ec0e7cfa584cd75a5db20ef4ac1a64293 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 14:58:34 -0700 Subject: [PATCH 0080/2239] bugfix: ngx.thread abortion did not abort the nginx resolver for ngx.socket.udp in time. --- src/ngx_http_lua_socket_tcp.c | 2 +- src/ngx_http_lua_socket_udp.c | 29 ++++++++++- t/094-uthread-exit.t | 95 +++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index e99445c1b7..8c837cc9a7 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -3888,4 +3888,4 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) ngx_resolve_name_done(rctx); } -# + diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 1f30a31297..7ff53ff52a 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -45,6 +45,7 @@ static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_udp_connect(ngx_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); +static void ngx_http_lua_udp_resolve_cleanup(void *data); enum { @@ -345,6 +346,9 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) saved_top = lua_gettop(L); + coctx = ctx->cur_co_ctx; + coctx->cleanup = ngx_http_lua_udp_resolve_cleanup; + if (ngx_resolve_name(rctx) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket fail to run resolver immediately"); @@ -375,7 +379,6 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; - coctx = ctx->cur_co_ctx; coctx->data = u; if (ctx->entered_content_phase) { @@ -413,6 +416,9 @@ ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) } lctx->cur_co_ctx = u->co_ctx; + + u->co_ctx->cleanup = NULL; + L = lctx->cur_co_ctx->co; dd("setting socket_ready to 1"); @@ -1421,3 +1427,24 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) return rc; } + +static void +ngx_http_lua_udp_resolve_cleanup(void *data) +{ + ngx_resolver_ctx_t *rctx; + ngx_http_lua_socket_udp_upstream_t *u; + ngx_http_lua_co_ctx_t *coctx = data; + + u = coctx->data; + if (u == NULL) { + return; + } + + rctx = u->resolved->ctx; + if (rctx == NULL) { + return; + } + + ngx_resolve_name_done(rctx); +} + diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index d6743a3f36..0a78c7776c 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -380,3 +380,98 @@ after --- no_error_log [error] + + +=== TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_resolve_cleanup) { + println("lua udp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua udp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 05d4a3b7e5da6aaa78a6c84bd2029263ac604cb5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 15:11:07 -0700 Subject: [PATCH 0081/2239] refactor: now we use ngx_http_lua_request_cleanup for complete cleanups in all the places. --- src/ngx_http_lua_util.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index d14a33829f..abc898b43f 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -904,6 +904,7 @@ ngx_http_lua_request_cleanup(void *data) } } + ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_del_all_threads(r, L, ctx); } @@ -1214,7 +1215,6 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_settop(L, 0); - ngx_http_lua_del_all_threads(r, L, ctx); ngx_http_lua_request_cleanup(r); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1268,7 +1268,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, no_parent: lua_settop(L, 0); - ngx_http_lua_del_all_threads(r, L, ctx); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; ngx_http_lua_request_cleanup(r); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " @@ -1858,7 +1858,6 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, &ctx->exec_uri); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); if (ctx->exec_uri.data[0] == '@') { @@ -1942,7 +1941,6 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, #endif ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); if ((ctx->exit_code == NGX_OK @@ -2198,7 +2196,6 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, "\"%V?%V\"", &r->uri, &r->args); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - ngx_http_lua_finalize_coroutines(r, ctx); ngx_http_lua_request_cleanup(r); return NGX_OK; @@ -2730,15 +2727,17 @@ ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } } - cc = ctx->user_co_ctx->elts; + if (ctx->user_co_ctx) { + cc = ctx->user_co_ctx->elts; - for (i = 0; i < ctx->user_co_ctx->nelts; i++) { - coctx = &cc[i]; - if (coctx->cleanup) { - coctx->cleanup(coctx); - coctx->cleanup = NULL; - coctx->co_status = NGX_HTTP_LUA_CO_DEAD; - /* TODO we could also free the user thread here */ + for (i = 0; i < ctx->user_co_ctx->nelts; i++) { + coctx = &cc[i]; + if (coctx->cleanup) { + coctx->cleanup(coctx); + coctx->cleanup = NULL; + coctx->co_status = NGX_HTTP_LUA_CO_DEAD; + /* TODO we could also free the user thread here */ + } } } From be896210d9905e293480b181621ffe9197234d8a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 15:27:35 -0700 Subject: [PATCH 0082/2239] bugfix: ngx.thread abortion did not abort tcpsock:connect() in time. --- src/ngx_http_lua_socket_tcp.c | 20 ++++++++ t/094-uthread-exit.t | 89 +++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 8c837cc9a7..3dc35531ca 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -91,6 +91,7 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_test_expect(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_tcp_connect_cleanup(void *data); enum { @@ -858,6 +859,8 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_AGAIN */ + coctx->cleanup = ngx_http_lua_tcp_connect_cleanup; + ngx_add_timer(c->write, u->connect_timeout); if (ctx->entered_content_phase) { @@ -2071,6 +2074,8 @@ ngx_http_lua_socket_connected_handler(ngx_http_request_t *r, ngx_connection_t *c; ngx_http_lua_loc_conf_t *llcf; + u->co_ctx->cleanup = NULL; + c = u->peer.connection; if (c->write->timedout) { @@ -3889,3 +3894,18 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) ngx_resolve_name_done(rctx); } + +static void +ngx_http_lua_tcp_connect_cleanup(void *data) +{ + ngx_http_lua_socket_tcp_upstream_t *u; + ngx_http_lua_co_ctx_t *coctx = data; + + u = coctx->data; + if (u == NULL) { + return; + } + + ngx_http_lua_socket_tcp_finalize(u->request, u); +} + diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 0a78c7776c..fd4ca8f2da 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -475,3 +475,92 @@ after --- no_error_log [error] + + +=== TEST 7: exit in user thread (entry thread is still pending on tcpsock:connect) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + sock:settimeout(12000) + local ok, err = sock:connect("8.8.4.4", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_connect_cleanup) { + println("lua tcp connect cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp connect cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 0e54fcd7aa5e27a4a607a929b3724fffe7893ddf Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 15:59:14 -0700 Subject: [PATCH 0083/2239] bugfix: ngx.thread abortion did not abort tcpsock:receive() in time. --- src/ngx_http_lua_socket_tcp.c | 20 +++++-- t/094-uthread-exit.t | 106 +++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 3dc35531ca..9e4fce73c3 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -91,7 +91,7 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, static ngx_int_t ngx_http_lua_test_expect(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_tcp_connect_cleanup(void *data); +static void ngx_http_lua_tcp_socket_cleanup(void *data); enum { @@ -859,7 +859,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_AGAIN */ - coctx->cleanup = ngx_http_lua_tcp_connect_cleanup; + coctx->cleanup = ngx_http_lua_tcp_socket_cleanup; ngx_add_timer(c->write, u->connect_timeout); @@ -891,6 +891,8 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket error retval handler"); + u->co_ctx->cleanup = NULL; + ngx_http_lua_socket_tcp_finalize(r, u); if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) { @@ -1111,6 +1113,8 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) u->read_event_handler = ngx_http_lua_socket_read_handler; u->write_event_handler = ngx_http_lua_socket_dummy_handler; + ctx->cur_co_ctx->cleanup = ngx_http_lua_tcp_socket_cleanup; + if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } @@ -2004,6 +2008,8 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, u->write_event_handler = ngx_http_lua_socket_dummy_handler; #endif + u->co_ctx->cleanup = NULL; + #if 0 if (u->eof) { ngx_http_lua_socket_tcp_finalize(r, u); @@ -2044,6 +2050,8 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_finalize(r, u); #endif + 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; @@ -2074,8 +2082,6 @@ ngx_http_lua_socket_connected_handler(ngx_http_request_t *r, ngx_connection_t *c; ngx_http_lua_loc_conf_t *llcf; - u->co_ctx->cleanup = NULL; - c = u->peer.connection; if (c->write->timedout) { @@ -3896,7 +3902,7 @@ ngx_http_lua_tcp_resolve_cleanup(void *data) static void -ngx_http_lua_tcp_connect_cleanup(void *data) +ngx_http_lua_tcp_socket_cleanup(void *data) { ngx_http_lua_socket_tcp_upstream_t *u; ngx_http_lua_co_ctx_t *coctx = data; @@ -3906,6 +3912,10 @@ ngx_http_lua_tcp_connect_cleanup(void *data) return; } + if (u->request == NULL) { + return; + } + ngx_http_lua_socket_tcp_finalize(u->request, u); } diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index fd4ca8f2da..1e8f5c63be 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -13,6 +13,7 @@ plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; #no_shuffle(); no_long_string(); @@ -540,8 +541,8 @@ M(timer-expire) { } } -F(ngx_http_lua_tcp_connect_cleanup) { - println("lua tcp connect cleanup") +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") } _EOC_ @@ -551,7 +552,106 @@ create user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 -lua tcp connect cleanup +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 8: exit in user thread (entry thread is still pending on tcpsock:receive) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 From c60ea6817fe0ebe88417dab90ead87201b5d73fd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 16:04:02 -0700 Subject: [PATCH 0084/2239] bugfix: ngx.thread abortion did not abort the reading iterators returned by tcpsock:receiveuntil() in time. --- src/ngx_http_lua_socket_tcp.c | 2 + t/094-uthread-exit.t | 105 ++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 9e4fce73c3..7ec0f88410 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2490,6 +2490,8 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) u->read_event_handler = ngx_http_lua_socket_read_handler; u->write_event_handler = ngx_http_lua_socket_dummy_handler; + ctx->cur_co_ctx->cleanup = ngx_http_lua_tcp_socket_cleanup; + if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 1e8f5c63be..ec0a156313 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -664,3 +664,108 @@ after --- no_error_log [error] + + +=== TEST 9: exit in user thread (entry thread is still pending on tcpsock:receiveuntil's iterator) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local it, err = sock:receiveuntil("\\r\\n") + if not it then + ngx.say("failed to receive until: ", err) + return + end + + sock:settimeout(12000) + + local data, err = it() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 1d05ac614900da8450235bcb5662af478e6a117b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 16:13:07 -0700 Subject: [PATCH 0085/2239] bugfix: ngx.thread abortion did not abort udpsock:receive() in time. --- src/ngx_http_lua_socket_udp.c | 26 ++++++++++ t/094-uthread-exit.t | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 7ff53ff52a..0a03e5d464 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -46,6 +46,7 @@ static ngx_int_t ngx_http_lua_udp_connect(ngx_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); +static void ngx_http_lua_udp_socket_cleanup(void *data); enum { @@ -891,6 +892,8 @@ ngx_http_lua_socket_udp_receive(lua_State *L) return luaL_error(L, "no request ctx found"); } + ctx->cur_co_ctx->cleanup = ngx_http_lua_udp_socket_cleanup; + if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } @@ -1126,6 +1129,8 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, u->read_event_handler = ngx_http_lua_socket_dummy_handler; + u->co_ctx->cleanup = NULL; + if (u->waiting) { u->waiting = 0; @@ -1196,6 +1201,8 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, u->read_event_handler = ngx_http_lua_socket_dummy_handler; + u->co_ctx->cleanup = NULL; + if (u->waiting) { u->waiting = 0; @@ -1448,3 +1455,22 @@ ngx_http_lua_udp_resolve_cleanup(void *data) ngx_resolve_name_done(rctx); } + +static void +ngx_http_lua_udp_socket_cleanup(void *data) +{ + ngx_http_lua_socket_udp_upstream_t *u; + ngx_http_lua_co_ctx_t *coctx = data; + + u = coctx->data; + if (u == NULL) { + return; + } + + if (u->request == NULL) { + return; + } + + ngx_http_lua_socket_udp_finalize(u->request, u); +} + diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index ec0a156313..ff5271af5f 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -769,3 +769,96 @@ after --- no_error_log [error] + + +=== TEST 10: exit in user thread (entry thread is still pending on udpsock:receive) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.udp() + + local ok, err = sock:setpeername("8.8.8.8", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_socket_cleanup) { + println("lua udp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua udp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 198e48d161bce86242dcb233872741d685d001d9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 16:40:16 -0700 Subject: [PATCH 0086/2239] bugfix: NULL pointer access might happen on u->co_ctx in *handle_success and *handle_error functions. this bug had appeared in the previous commits. --- src/ngx_http_lua_socket_tcp.c | 12 +++++++++--- src/ngx_http_lua_socket_udp.c | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 7ec0f88410..d6e61e245a 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -891,7 +891,9 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket error retval handler"); - u->co_ctx->cleanup = NULL; + if (u->co_ctx) { + u->co_ctx->cleanup = NULL; + } ngx_http_lua_socket_tcp_finalize(r, u); @@ -2008,7 +2010,9 @@ ngx_http_lua_socket_handle_success(ngx_http_request_t *r, u->write_event_handler = ngx_http_lua_socket_dummy_handler; #endif - u->co_ctx->cleanup = NULL; + if (u->co_ctx) { + u->co_ctx->cleanup = NULL; + } #if 0 if (u->eof) { @@ -2050,7 +2054,9 @@ ngx_http_lua_socket_handle_error(ngx_http_request_t *r, ngx_http_lua_socket_tcp_finalize(r, u); #endif - u->co_ctx->cleanup = NULL; + 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; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 0a03e5d464..9eb2a6c289 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1129,7 +1129,9 @@ ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r, u->read_event_handler = ngx_http_lua_socket_dummy_handler; - u->co_ctx->cleanup = NULL; + if (u->co_ctx) { + u->co_ctx->cleanup = NULL; + } if (u->waiting) { u->waiting = 0; @@ -1201,7 +1203,9 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, u->read_event_handler = ngx_http_lua_socket_dummy_handler; - u->co_ctx->cleanup = NULL; + if (u->co_ctx) { + u->co_ctx->cleanup = NULL; + } if (u->waiting) { u->waiting = 0; From 9e127b09a71f760c342b63b4cbf75fdfe6752dd8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 17:06:16 -0700 Subject: [PATCH 0087/2239] bugfix: always remove the read event timer during downstream cosocket finalization if it is not removed yet. --- src/ngx_http_lua_socket_tcp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index bcd9b97204..84f9b908d0 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2171,6 +2171,11 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, if (u->is_downstream) { r->read_event_handler = ngx_http_block_reading; + + if (r->connection->read->timer_set) { + ngx_del_timer(r->connection->read); + } + u->peer.connection = NULL; return; } From 94e623f6fe5152fbbee83bf526b7978e87b86397 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 17:08:25 -0700 Subject: [PATCH 0088/2239] added a (passing) test for aborting the receive() invocation on the ngx.req.socket() object. --- t/094-uthread-exit.t | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index ff5271af5f..637dea6cd6 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -862,3 +862,90 @@ after --- no_error_log [error] + + +=== TEST 11: exit in user thread (entry thread is still pending on reqsock:receive) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.req.socket() + + sock:settimeout(12000) + + local data, err = sock:receive(1024) + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + } +--- request +POST /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 51b5421fe017b5e72588c1a3bea05511367e4759 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 17:27:03 -0700 Subject: [PATCH 0089/2239] refactor: changed the way ngx.req.read_body() handles r->main->count, which opens the door for abortion in the middile. --- src/ngx_http_lua_req_body.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 98d3873582..06e97e1d08 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -110,6 +110,8 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) rc = ngx_http_read_client_request_body(r, ngx_http_lua_req_body_post_read); + r->main->count--; + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to read request body"); } @@ -144,10 +146,6 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); -#if defined(nginx_version) && nginx_version >= 8011 - r->main->count--; -#endif - if (ctx->waiting_more_body) { ctx->waiting_more_body = 0; From 7c65ad1b904495c5dcc2c663251f2784a94381e8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 17:45:23 -0700 Subject: [PATCH 0090/2239] bugfix: ngx.thread abortion did not abort ngx.req.read_body() in time. --- src/ngx_http_lua_req_body.c | 25 +++++++++++ t/094-uthread-exit.t | 83 +++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 0207150901..432aec6240 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -23,6 +23,7 @@ static int ngx_http_lua_ngx_req_body_finish(lua_State *L); static ngx_int_t ngx_http_lua_write_request_body(ngx_http_request_t *r, ngx_chain_t *body); static ngx_int_t ngx_http_lua_read_body_resume(ngx_http_request_t *r); +static void ngx_http_lua_req_body_cleanup(void *data); void @@ -123,6 +124,9 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) ctx->waiting_more_body = 1; ctx->req_body_reader_co_ctx = coctx; + coctx->cleanup = ngx_http_lua_req_body_cleanup; + coctx->data = r; + return lua_yield(L, 0); } @@ -152,6 +156,8 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) coctx = ctx->req_body_reader_co_ctx; ctx->cur_co_ctx = coctx; + coctx->cleanup = NULL; + if (ctx->entered_content_phase) { (void) ngx_http_lua_read_body_resume(r); @@ -1110,3 +1116,22 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) return rc; } + +static void +ngx_http_lua_req_body_cleanup(void *data) +{ + ngx_http_request_t *r; + ngx_http_lua_co_ctx_t *coctx = data; + + r = coctx->data; + if (r == NULL) { + return; + } + + r->read_event_handler = ngx_http_block_reading; + + if (r->connection->read->timer_set) { + ngx_del_timer(r->connection->read); + } +} + diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 637dea6cd6..837a0c82bb 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -949,3 +949,86 @@ after --- no_error_log [error] + + +=== TEST 12: exit in user thread (entry thread is still pending on ngx.req.read_body) +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + + ngx.req.read_body() + + ngx.say("end") + '; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_req_body_cleanup) { + println("lua req body cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua req body cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From 33756e1cd0380e918690eb61bec10b0ef70fab46 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 18:02:20 -0700 Subject: [PATCH 0091/2239] bugfix: ngx.thread abortion did not abort tcpsock:send() in time. --- src/ngx_http_lua_socket_tcp.c | 2 + t/065-tcp-socket-timeout.t | 99 ++++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index bfcab962fa..7f53b03efb 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1625,6 +1625,8 @@ ngx_http_lua_socket_tcp_send(lua_State *L) /* rc == NGX_AGAIN */ + ctx->cur_co_ctx->cleanup = ngx_http_lua_tcp_socket_cleanup; + if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index f7140fee86..150ed23b7c 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -17,6 +17,10 @@ BEGIN { use lib 'lib'; use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = $t::StapThread::GCScript; +our $StapScript = $t::StapThread::StapScript; repeat_each(2); @@ -30,7 +34,7 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; log_level("debug"); no_long_string(); -no_diff(); +#no_diff(); run_tests(); __DATA__ @@ -574,3 +578,96 @@ lua tcp socket send timeout: 102 lua tcp socket connect timeout: 60000 lua tcp socket write timed out + + +=== TEST 16: exit in user thread (entry thread is still pending on tcpsock:send) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + 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 + + sock:settimeout(12000) + + local bytes, ok = sock:send("get helloworld!") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + From d3e2e646bd11eeb25d70cc2d973304dbc8ec37f3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 19:16:25 -0700 Subject: [PATCH 0092/2239] bugfix: ngx.flush(true) might not return immediately when it should. --- src/ngx_http_lua_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index d0212f9042..fb2cbfcf2d 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -554,7 +554,7 @@ ngx_http_lua_ngx_flush(lua_State *L) wev = r->connection->write; if (wev->ready && wev->delayed) { - return lua_yield(L, 0); + return 0; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); From 2bea02618cf7f00562958aaa5ccbf0523edfd240 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 19:21:10 -0700 Subject: [PATCH 0093/2239] bugfix: the write event timer might not be removed in time in ngx.flush(true) when ngx_handle_write_event failed. --- src/ngx_http_lua_output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index fb2cbfcf2d..84d36e2c66 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -564,6 +564,9 @@ ngx_http_lua_ngx_flush(lua_State *L) } if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { + if (wev->timer_set) { + ngx_del_timer(wev); + } return luaL_error(L, "connection broken"); } From c25f2df8aa7085c70e4e0da7b9ba471fcb62dab2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 20:46:40 -0700 Subject: [PATCH 0094/2239] bugfix: ngx.thread abortion did not abort ngx.flush(true) in time. --- src/ngx_http_lua_output.c | 36 ++++++++++++++ t/057-flush-timeout.t | 102 +++++++++++++++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index fce57579a8..a2088a44be 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -15,6 +15,7 @@ static int ngx_http_lua_ngx_flush(lua_State *L); static int ngx_http_lua_ngx_eof(lua_State *L); static int ngx_http_lua_ngx_send_headers(lua_State *L); static int ngx_http_lua_ngx_echo(lua_State *L, unsigned newline); +static void ngx_http_lua_flush_cleanup(void *data); static int @@ -570,6 +571,9 @@ ngx_http_lua_ngx_flush(lua_State *L) return luaL_error(L, "connection broken"); } + coctx->cleanup = ngx_http_lua_flush_cleanup; + coctx->data = r; + return lua_yield(L, 0); } @@ -694,6 +698,8 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) c = r->connection; + ctx->cur_co_ctx->cleanup = NULL; + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -718,3 +724,33 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) return rc; } + +static void +ngx_http_lua_flush_cleanup(void *data) +{ + ngx_http_request_t *r; + ngx_event_t *wev; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx = data; + + coctx->flushing = 0; + + r = coctx->data; + if (r == NULL) { + return; + } + + wev = r->connection->write; + + if (wev && wev->timer_set) { + ngx_del_timer(wev); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->flushing_coros--; +} + diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 195b528811..431d5cf38d 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -18,6 +18,10 @@ BEGIN { 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(); @@ -26,7 +30,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 1 + 1); +plan tests => repeat_each() * (blocks() * 1 + 2); #no_diff(); no_long_string(); @@ -110,3 +114,99 @@ del timer 1234 [error] --- timeout: 3 + + +=== TEST 3: exit in user thread (entry thread is still pending on ngx.flush) +--- config + send_timeout 200ms; + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + + ngx.say("hello, world!") + ngx.flush(true) + + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} + +/* +F(ngx_http_finalize_request) { + printf("finalize request: c:%d, a:%d, cb:%d, rb:%d\n", $r->main->count, + $r == $r->connection->data, $r->connection->buffered, $r->buffered) +} + +F(ngx_http_set_write_handler) { + println("set write handler") +} +*/ + +F(ngx_http_lua_flush_cleanup) { + println("lua flush cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +lua flush cleanup +delete timer 200 +delete thread 2 +delete thread 1 +add timer 200 +expire timer 200 +free request + +--- ignore_response +--- no_error_log +[error] + From 8f2f149c2d7c971caf269943aba79464dae3a8fa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 24 Sep 2012 22:31:52 -0700 Subject: [PATCH 0095/2239] updated t::StapThread to reflect recent changes. --- t/StapThread.pm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/t/StapThread.pm b/t/StapThread.pm index 734b6561c7..62093c7397 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -77,11 +77,6 @@ F(ngx_http_lua_post_thread) { printf("post thread %d\n", id) } -F(ngx_http_lua_co_cleanup) { - id = gen_id(@cast($data, "ngx_http_lua_co_ctx_t")->co) - printf("co cleanup called for thread %d\n", id) -} - M(timer-add) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) From 3b48d03d1d43dff12893e319828a51de94329221 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Sep 2012 11:48:13 -0700 Subject: [PATCH 0096/2239] bugfix: aborting ngx.thread coroutines with pending subrequests caused problems and now we just prohibit this by raising Lua exceptions and aborting the main request. --- src/ngx_http_lua_common.h | 4 + src/ngx_http_lua_control.c | 6 + src/ngx_http_lua_subrequest.c | 3 + src/ngx_http_lua_uri.c | 3 + src/ngx_http_lua_util.c | 4 + src/ngx_http_lua_util.h | 7 + t/094-uthread-exit.t | 255 ++++++++++++++++++++++++++++++++++ t/095-uthread-exec.t | 82 +++++++++++ 8 files changed, 364 insertions(+) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 31d1a93f43..2d81b21fbb 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -343,6 +343,10 @@ typedef struct ngx_http_lua_ctx_s { unsigned buffering:1; /* HTTP 1.0 response body buffering flag */ + unsigned no_abort:1; /* prohibit "world abortion" via ngx.exit() + and etc */ + + unsigned fatal:1; /* error is fatal */ } ngx_http_lua_ctx_t; diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index f57394d9a6..1655a6b1da 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -93,6 +93,8 @@ ngx_http_lua_ngx_exec(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + ngx_http_lua_check_if_abortable(L, ctx); + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { @@ -226,6 +228,8 @@ ngx_http_lua_ngx_redirect(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + ngx_http_lua_check_if_abortable(L, ctx); + if (ctx->headers_sent) { return luaL_error(L, "attempt to call ngx.redirect after sending out " "the headers"); @@ -300,6 +304,8 @@ ngx_http_lua_ngx_exit(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); + ngx_http_lua_check_if_abortable(L, ctx); + rc = (ngx_int_t) luaL_checkinteger(L, 1); if (rc >= NGX_HTTP_SPECIAL_RESPONSE && ctx->headers_sent) { diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index b085ad19a2..5983597d7b 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -547,6 +547,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) ngx_array_destroy(extra_vars); } + ctx->no_abort = 1; + return lua_yield(L, 0); } @@ -858,6 +860,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) if (pr_coctx->pending_subreqs == 0) { dd("all subrequests are done"); + pr_ctx->no_abort = 0; pr_ctx->resume_handler = ngx_http_lua_subrequest_resume; pr_ctx->cur_co_ctx = pr_coctx; } diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index 05e5b4f5f6..531782e77a 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -81,7 +81,10 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua set uri jump to \"%V\"", &r->uri); + ngx_http_lua_check_if_abortable(L, ctx); + r->uri_changed = 1; + return lua_yield(L, 0); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index abc898b43f..833ee598c1 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1219,6 +1219,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, dd("headers sent? %d", ctx->headers_sent ? 1 : 0); + if (ctx->fatal) { + return NGX_ERROR; + } + return ctx->headers_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index f9836bebec..10ba703f58 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -132,6 +132,13 @@ ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); +#define ngx_http_lua_check_if_abortable(L, ctx) \ + if ((ctx)->no_abort) { \ + ctx->fatal = 1; \ + return luaL_error(L, "attempt to abort with pending subrequests"); \ + } + + #define ngx_http_lua_init_ctx(ctx) \ ngx_memzero(ctx, sizeof(ngx_http_lua_ctx_t)); \ ctx->ctx_ref = LUA_NOREF; \ diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 837a0c82bb..cfb8377fa6 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -1032,3 +1032,258 @@ after --- no_error_log [error] + + +=== TEST 13: exit in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 14: exit in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.create(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} + +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 15: exit in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.create(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 432ea47b44..7311047d22 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -254,3 +254,85 @@ hello foo --- no_error_log [error] + + +=== TEST 5: exec in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } + + location = /foo { + echo hello world; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + From 3a30a00ff31bb32c28603ae6cf2d6317422346d2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Sep 2012 11:57:21 -0700 Subject: [PATCH 0097/2239] added some (passing) tests for ngx.redirect + ngx.thread. --- t/096-uthread-redirect.t | 189 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 t/096-uthread-redirect.t diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t new file mode 100644 index 0000000000..ebdea7d8e4 --- /dev/null +++ b/t/096-uthread-redirect.t @@ -0,0 +1,189 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ngx.redirect() in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.create(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 2: redirect in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("end") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + From 7ba928b52ae8c52ad3b0065e16ecd11b860b0eb4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Sep 2012 16:21:27 -0700 Subject: [PATCH 0098/2239] bugfix: the ngx.thread API did not work in rewrite_by_lua*. --- src/ngx_http_lua_req_body.c | 9 + src/ngx_http_lua_rewriteby.c | 26 +- src/ngx_http_lua_uthread.h | 6 +- t/023-rewrite/uthread-exec.t | 343 ++++++++ t/023-rewrite/uthread-exit.t | 1316 ++++++++++++++++++++++++++++++ t/023-rewrite/uthread-redirect.t | 191 +++++ t/023-rewrite/uthread.t | 1091 +++++++++++++++++++++++++ t/097-uthread-rewrite.t | 338 ++++++++ t/StapThread.pm | 21 + 9 files changed, 3331 insertions(+), 10 deletions(-) create mode 100644 t/023-rewrite/uthread-exec.t create mode 100644 t/023-rewrite/uthread-exit.t create mode 100644 t/023-rewrite/uthread-redirect.t create mode 100644 t/023-rewrite/uthread.t create mode 100644 t/097-uthread-rewrite.t diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 432aec6240..6031a65b86 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -1121,6 +1121,7 @@ static void ngx_http_lua_req_body_cleanup(void *data) { ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx = data; r = coctx->data; @@ -1133,5 +1134,13 @@ ngx_http_lua_req_body_cleanup(void *data) if (r->connection->read->timer_set) { ngx_del_timer(r->connection->read); } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + ctx->waiting_more_body = 0; + r->keepalive = 0; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index a29adbe7b7..d58f5e109d 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -91,10 +91,6 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) dd("entered? %d", (int) ctx->entered_rewrite_phase); - if (ctx->waiting_more_body) { - return NGX_DONE; - } - if (ctx->entered_rewrite_phase) { dd("rewriteby: calling wev handler"); rc = ctx->resume_handler(r); @@ -107,12 +103,16 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) return rc; } + if (ctx->waiting_more_body) { + return NGX_DONE; + } + if (llcf->force_read_body && !ctx->read_body_done) { r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; - rc = ngx_http_read_client_request_body(r, + rc = ngx_http_read_client_request_body(r, ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -288,12 +288,24 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + + if (rc == NGX_OK) { + return NGX_DECLINED; + } + + return rc; } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + + if (rc == NGX_OK) { + return NGX_DECLINED; + } + + return rc; } return NGX_DECLINED; diff --git a/src/ngx_http_lua_uthread.h b/src/ngx_http_lua_uthread.h index 9637e465fa..4180fec0a0 100644 --- a/src/ngx_http_lua_uthread.h +++ b/src/ngx_http_lua_uthread.h @@ -5,15 +5,15 @@ #include "ngx_http_lua_common.h" -#define ngx_http_lua_is_thread(ctx) \ +#define ngx_http_lua_is_thread(ctx) \ ((ctx)->cur_co_ctx->is_uthread || (ctx)->cur_co_ctx == &(ctx)->entry_co_ctx) -#define ngx_http_lua_is_entry_thread(ctx) \ +#define ngx_http_lua_is_entry_thread(ctx) \ ((ctx)->cur_co_ctx == &ctx->entry_co_ctx) -#define ngx_http_lua_entry_thread_alive(ctx) \ +#define ngx_http_lua_entry_thread_alive(ctx) \ ((ctx)->entry_co_ctx.co_ref != LUA_NOREF) diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t new file mode 100644 index 0000000000..7591b0fc7f --- /dev/null +++ b/t/023-rewrite/uthread-exec.t @@ -0,0 +1,343 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: exec in user thread (entry still pending) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.exec("/foo") + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("hello") + '; + content_by_lua return; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 2: exec in user thread (entry already quits) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + '; + content_by_lua return; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 3: exec in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + ngx.sleep(1) + '; + content_by_lua return; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 4: exec in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + function g() + ngx.sleep(1) + end + + ngx.thread.create(f) + ngx.thread.create(g) + '; + content_by_lua return; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 5: exec in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.create(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } + + location = /foo { + echo hello world; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t new file mode 100644 index 0000000000..5c500fb99f --- /dev/null +++ b/t/023-rewrite/uthread-exit.t @@ -0,0 +1,1316 @@ +# 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; + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: exit in user thread (entry thread is still pending to run) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +M(timer-add) { + if ($arg2 == 1000) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 1000) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 1000) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before +hello in thread +--- no_error_log +[error] + + + +=== TEST 2: exit in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 3: exit in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f") + ngx.exit(0) + end + + function g() + ngx.sleep(1) + ngx.say("g") + end + + ngx.thread.create(f) + ngx.thread.create(g) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +delete thread 4 +free request + +--- response_body +end +f +--- no_error_log +[error] + + + +=== TEST 4: exit in user thread (entry already quits) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("exiting the user thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +after +exiting the user thread +--- no_error_log +[error] + + + +=== TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_resolve_cleanup) { + println("lua tcp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua tcp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_resolve_cleanup) { + println("lua udp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua udp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 7: exit in user thread (entry thread is still pending on tcpsock:connect) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + sock:settimeout(12000) + local ok, err = sock:connect("8.8.4.4", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 8: exit in user thread (entry thread is still pending on tcpsock:receive) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 9: exit in user thread (entry thread is still pending on tcpsock:receiveuntil's iterator) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local it, err = sock:receiveuntil("\\r\\n") + if not it then + ngx.say("failed to receive until: ", err) + return + end + + sock:settimeout(12000) + + local data, err = it() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 10: exit in user thread (entry thread is still pending on udpsock:receive) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.socket.udp() + + local ok, err = sock:setpeername("8.8.8.8", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_socket_cleanup) { + println("lua udp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua udp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 11: exit in user thread (entry thread is still pending on reqsock:receive) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + local sock = ngx.req.socket() + + sock:settimeout(12000) + + local data, err = sock:receive(1024) + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +POST /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 12: exit in user thread (entry thread is still pending on ngx.req.read_body) +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + + ngx.req.read_body() + + ngx.say("end") + '; + content_by_lua return; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_req_body_cleanup) { + println("lua req body cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua req body cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 13: exit in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 14: exit in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.create(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} + +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 15: exit in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.create(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + content_by_lua return; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t new file mode 100644 index 0000000000..78f4ba44f7 --- /dev/null +++ b/t/023-rewrite/uthread-redirect.t @@ -0,0 +1,191 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ngx.redirect() in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.create(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + content_by_lua return; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 2: redirect in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + diff --git a/t/023-rewrite/uthread.t b/t/023-rewrite/uthread.t new file mode 100644 index 0000000000..b3bdcbafb6 --- /dev/null +++ b/t/023-rewrite/uthread.t @@ -0,0 +1,1091 @@ +# 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; + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 1); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: simple user thread without I/O +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval +<<'_EOC_' . $::StapScript; + +F(ngx_http_lua_send_chain_link) { + printf("send link %p\n", $in) +} + +F(ngx_http_core_content_phase) { + println("core content phase") +} + +_EOC_ +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 2: two simple user threads without I/O +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("in thread 1") + end + + function g() + ngx.say("in thread 2") + end + + ngx.say("before 1") + ngx.thread.create(f) + ngx.say("after 1") + + ngx.say("before 2") + ngx.thread.create(g) + ngx.say("after 2") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +create 3 in 1 +create user thread 3 in 1 +delete thread 3 +delete thread 1 +delete thread 4 + +--- response_body +before 1 +in thread 1 +after 1 +before 2 +in thread 2 +after 2 +--- no_error_log +[error] + + + +=== TEST 3: simple user thread with sleep +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before sleep") + ngx.sleep(0.1) + ngx.say("after sleep") + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before sleep +after thread create +after sleep +--- no_error_log +[error] + + + +=== TEST 4: two simple user threads with sleep +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("1: before sleep") + ngx.sleep(0.2) + ngx.say("1: after sleep") + end + + function g() + ngx.say("2: before sleep") + ngx.sleep(0.1) + ngx.say("2: after sleep") + end + + ngx.say("1: before thread create") + ngx.thread.create(f) + ngx.say("1: after thread create") + + ngx.say("2: before thread create") + ngx.thread.create(g) + ngx.say("2: after thread create") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 3 +delete thread 2 +delete thread 4 + +--- response_body +1: before thread create +1: before sleep +1: after thread create +2: before thread create +2: before sleep +2: after thread create +2: after sleep +1: after sleep +--- no_error_log +[error] + + + +=== TEST 5: error in user thread +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.blah() + end + + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +lua thread aborted: runtime error: [string "rewrite_by_lua"]:3: attempt to call field 'blah' (a nil value) + + + +=== TEST 6: simple user threads doing a single subrequest (entry quits early) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before capture") + res = ngx.location.capture("/proxy") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/foo; + } + + location /foo { + echo_sleep 0.1; + echo -n hello world; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +after capture: hello world +--- no_error_log +[error] + + + +=== TEST 7: simple user threads doing a single subrequest (entry also does a subrequest and quits early) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +capture: hello bar +after capture: hello foo +--- no_error_log +[error] + + + +=== TEST 8: simple user threads doing a single subrequest (entry also does a subrequest and quits late) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.create(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +after capture: hello foo +capture: hello bar +--- no_error_log +[error] + + + +=== TEST 9: two simple user threads doing single subrequests (entry also does a subrequest and quits between) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("f: before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("f: after capture: ", res.body) + end + + function g() + ngx.say("g: before capture") + local res = ngx.location.capture("/proxy?bah") + ngx.say("g: after capture: ", res.body) + end + + ngx.say("before thread 1 create") + ngx.thread.create(f) + ngx.say("after thread 1 create") + + ngx.say("before thread 2 create") + ngx.thread.create(g) + ngx.say("after thread 2 create") + + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } + + location /bah { + echo_sleep 0.3; + echo -n hello bah; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 2 +delete thread 1 +delete thread 3 +delete thread 4 + +--- response_body +before thread 1 create +f: before capture +after thread 1 create +before thread 2 create +g: before capture +after thread 2 create +f: after capture: hello foo +capture: hello bar +g: after capture: hello bah +--- no_error_log +[error] + + + +=== TEST 10: nested user threads +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.create(f) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 3 +delete thread 1 +delete thread 2 +delete thread 4 + +--- response_body +before f +before g +hello in g() +after f +after g +--- no_error_log +[error] + + + +=== TEST 11: nested user threads (with I/O) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.sleep(0.1) + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.create(f) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 1 +delete thread 2 +delete thread 3 +delete thread 4 + +--- response_body +before f +before g +after f +after g +hello in g() +--- no_error_log +[error] + + + +=== TEST 12: coroutine status of a running user thread +--- config + location /lua { + rewrite_by_lua ' + local co + function f() + co = coroutine.running() + ngx.sleep(0.1) + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +status: running +--- no_error_log +[error] + + + +=== TEST 13: coroutine status of a dead user thread +--- config + location /lua { + rewrite_by_lua ' + local co + function f() + co = coroutine.running() + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +status: dead +--- no_error_log +[error] + + + +=== TEST 14: coroutine status of a "normal" user thread +--- config + location /lua { + rewrite_by_lua ' + local co + function f() + co = coroutine.running() + local co2 = coroutine.create(g) + coroutine.resume(co2) + end + + function g() + ngx.sleep(0.1) + end + + ngx.thread.create(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +delete thread 1 +delete thread 2 +delete thread 4 + +--- response_body +status: normal +--- no_error_log +[error] + + + +=== TEST 15: creating user threads in a user coroutine +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("before g") + ngx.thread.create(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + local co = coroutine.create(f) + coroutine.resume(co) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 3 +delete thread 1 +delete thread 4 + +--- response_body +before f +before g +hello in g() +after g +after f +--- no_error_log +[error] + + + +=== TEST 16: manual time slicing between a user thread and the entry thread +--- config + location /lua { + rewrite_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + ngx.say("1") + ngx.thread.create(f) + ngx.say("2") + yield(self) + ngx.say("3") + yield(self) + ngx.say("4") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +0 +1 +f 1 +2 +f 2 +3 +f 3 +4 +--- no_error_log +[error] + + + +=== TEST 17: manual time slicing between two user threads +--- config + location /lua { + rewrite_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + function g() + local self = coroutine.running() + ngx.say("g 1") + yield(self) + ngx.say("g 2") + yield(self) + ngx.say("g 3") + end + + ngx.thread.create(f) + ngx.thread.create(g) + ngx.say("done") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3 +delete thread 4 + +--- response_body +f 1 +g 1 +f 2 +done +g 2 +f 3 +g 3 +--- no_error_log +[error] + + + +=== TEST 18: entry thread and a user thread flushing at the same time +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello in thread") + coroutine.yield(coroutine.running) + ngx.flush(true) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + ngx.flush(true) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 19: two user threads flushing at the same time +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.say("hello from f") + ngx.flush(true) + end + + function g() + ngx.say("hello from g") + ngx.flush(true) + end + + ngx.thread.create(f) + ngx.thread.create(g) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3|create 2 in 1 +create user thread 2 in 1 +delete thread 2 +create 3 in 1 +create user thread 3 in 1 +delete thread 3 +delete thread 1) +delete thread 4$ + +--- response_body +hello from f +hello from g +--- no_error_log +[error] + + + +=== TEST 20: user threads + ngx.socket.tcp +--- config + location /lua { + rewrite_by_lua ' + function f() + 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 + local bytes, err = sock:send("flush_all\\r\\n") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +after +received: OK +--- no_error_log +[error] + + + +=== TEST 21: user threads + ngx.socket.udp +--- config + location /lua { + rewrite_by_lua ' + function f() + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("127.0.0.1", 12345) + local bytes, err = sock:send("blah") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- udp_listen: 12345 +--- udp_query: blah +--- udp_reply: hello udp +--- response_body +before +after +received: hello udp +--- no_error_log +[error] + + + +=== TEST 22: simple user thread with ngx.req.read_body() +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.req.read_body() + local body = ngx.req.get_body_data() + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2) +delete thread 3$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + + + +=== TEST 23: simple user thread with ngx.req.socket() +--- config + location /lua { + rewrite_by_lua ' + function f() + local sock = ngx.req.socket() + local body, err = sock:receive(11) + if not body then + ngx.say("failed to read body: ", err) + return + end + + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.create(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2) +delete thread 3$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t new file mode 100644 index 0000000000..addc29885f --- /dev/null +++ b/t/097-uthread-rewrite.t @@ -0,0 +1,338 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: rewrite in user thread (entry still pending) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.req.set_uri("/foo", true) + end + + ngx.thread.create(f) + ngx.sleep(1) + ngx.say("hello") + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 2: rewrite in user thread (entry already quits) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.req.set_uri("/foo", true) + end + + ngx.thread.create(f) + '; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 3: rewrite in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.req.set_uri("/foo", true) + end + + ngx.thread.create(f) + ngx.sleep(1) + '; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 4: rewrite in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.req.set_uri("/foo", true) + end + + function g() + ngx.sleep(1) + end + + ngx.thread.create(f) + ngx.thread.create(g) + '; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 5: rewrite in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + rewrite_by_lua ' + function f() + ngx.sleep(0.1) + ngx.req.set_uri("/foo", true) + end + + ngx.thread.create(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } + + location = /foo { + echo hello world; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/StapThread.pm b/t/StapThread.pm index 62093c7397..8b91f0d3f9 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -163,6 +163,7 @@ F(ngx_http_lua_run_posted_threads) { F(ngx_http_finalize_request) { printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); + #print_ubacktrace() } M(http-lua-user-coroutine-create) { @@ -174,6 +175,26 @@ 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_req_body_cleanup) { + println("lua req body cleanup") +} + +F(ngx_http_read_client_request_body) { + println("read client request body") +} + +F(ngx_http_lua_finalize_coroutines) { + println("finalize coroutines") +} + +F(ngx_http_lua_ngx_exit) { + println("ngx.exit() called") +} + +F(ngx_http_lua_sleep_resume) { + println("lua sleep resume") +} _EOC_ 1; From f4e8894e2dc9efc47ab72c09189b50dd09fe0fa3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Sep 2012 16:37:56 -0700 Subject: [PATCH 0099/2239] api: renamed ngx.thread.create() to ngx.thread.spawn(). --- src/ngx_http_lua_uthread.c | 2 +- t/023-rewrite/uthread-exec.t | 12 +++---- t/023-rewrite/uthread-exit.t | 32 ++++++++--------- t/023-rewrite/uthread-redirect.t | 4 +-- t/023-rewrite/uthread.t | 60 ++++++++++++++++---------------- t/057-flush-timeout.t | 2 +- t/065-tcp-socket-timeout.t | 2 +- t/093-uthread.t | 60 ++++++++++++++++---------------- t/094-uthread-exit.t | 32 ++++++++--------- t/095-uthread-exec.t | 12 +++---- t/096-uthread-redirect.t | 4 +-- t/097-uthread-rewrite.t | 12 +++---- 12 files changed, 117 insertions(+), 117 deletions(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 97cca8661f..f664a2ae58 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -20,7 +20,7 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) lua_newtable(L); lua_pushcfunction(L, ngx_http_lua_uthread_create); - lua_setfield(L, -2, "create"); + lua_setfield(L, -2, "spawn"); lua_setfield(L, -2, "thread"); } diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index 7591b0fc7f..ce7d2396af 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -28,7 +28,7 @@ __DATA__ ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) ngx.say("hello") '; @@ -64,7 +64,7 @@ i am foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) '; content_by_lua return; } @@ -98,7 +98,7 @@ i am foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) '; content_by_lua return; @@ -184,8 +184,8 @@ hello foo ngx.sleep(1) end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) '; content_by_lua return; } @@ -270,7 +270,7 @@ hello foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture("/sleep") ngx.say("end") diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index 5c500fb99f..d773fdd70e 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -31,7 +31,7 @@ __DATA__ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.sleep(1) ngx.say("end") @@ -96,7 +96,7 @@ hello in thread end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.sleep(1) ngx.say("end") @@ -185,8 +185,8 @@ after ngx.say("g") end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) ngx.say("end") '; content_by_lua return; @@ -271,7 +271,7 @@ f end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -309,7 +309,7 @@ exiting the user thread end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() local ok, err = sock:connect("www.google.com", 80) @@ -406,7 +406,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() local ok, err = sock:setpeername("www.google.com", 80) @@ -501,7 +501,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) @@ -592,7 +592,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() @@ -693,7 +693,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() @@ -800,7 +800,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() @@ -895,7 +895,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.req.socket() @@ -985,7 +985,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.req.read_body() @@ -1070,7 +1070,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.location.capture("/sleep") @@ -1151,7 +1151,7 @@ attempt to abort with pending subrequests ngx.exit(0) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture("/sleep") ngx.say("end") @@ -1235,7 +1235,7 @@ attempt to abort with pending subrequests ngx.exit(0) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture_multi{ {"/echo"}, diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t index 78f4ba44f7..53f56c3744 100644 --- a/t/023-rewrite/uthread-redirect.t +++ b/t/023-rewrite/uthread-redirect.t @@ -31,7 +31,7 @@ __DATA__ ngx.redirect(301) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture_multi{ {"/echo"}, @@ -121,7 +121,7 @@ attempt to abort with pending subrequests ngx.redirect(301) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) ngx.say("end") '; diff --git a/t/023-rewrite/uthread.t b/t/023-rewrite/uthread.t index b3bdcbafb6..10016ff202 100644 --- a/t/023-rewrite/uthread.t +++ b/t/023-rewrite/uthread.t @@ -29,7 +29,7 @@ __DATA__ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -78,11 +78,11 @@ after end ngx.say("before 1") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after 1") ngx.say("before 2") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after 2") '; content_by_lua return; @@ -124,7 +124,7 @@ after 2 end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") '; content_by_lua return; @@ -167,11 +167,11 @@ after sleep end ngx.say("1: before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("1: after thread create") ngx.say("2: before thread create") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("2: after thread create") '; content_by_lua return; @@ -212,7 +212,7 @@ delete thread 4 ngx.blah() end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -245,7 +245,7 @@ lua thread aborted: runtime error: [string "rewrite_by_lua"]:3: attempt to call end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") '; content_by_lua return; @@ -291,7 +291,7 @@ after capture: hello world end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) @@ -344,7 +344,7 @@ after capture: hello foo end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) @@ -404,11 +404,11 @@ capture: hello bar end ngx.say("before thread 1 create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread 1 create") ngx.say("before thread 2 create") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after thread 2 create") local res = ngx.location.capture("/proxy?bar") @@ -470,7 +470,7 @@ g: after capture: hello bah rewrite_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -479,7 +479,7 @@ g: after capture: hello bah end ngx.say("before f") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after f") '; content_by_lua return; @@ -515,7 +515,7 @@ after g rewrite_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -525,7 +525,7 @@ after g end ngx.say("before f") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after f") '; content_by_lua return; @@ -565,7 +565,7 @@ hello in g() ngx.sleep(0.1) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; content_by_lua return; @@ -597,7 +597,7 @@ status: running co = coroutine.running() end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; content_by_lua return; @@ -635,7 +635,7 @@ status: dead ngx.sleep(0.1) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; content_by_lua return; @@ -665,7 +665,7 @@ status: normal rewrite_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -722,7 +722,7 @@ after f ngx.say("0") yield(self) ngx.say("1") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("2") yield(self) ngx.say("3") @@ -780,8 +780,8 @@ f 3 ngx.say("g 3") end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) ngx.say("done") '; content_by_lua return; @@ -824,7 +824,7 @@ g 3 end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.flush(true) '; @@ -864,8 +864,8 @@ after ngx.flush(true) end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) '; content_by_lua return; } @@ -924,7 +924,7 @@ hello from g end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -972,7 +972,7 @@ received: OK end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -1011,7 +1011,7 @@ received: hello udp end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; @@ -1059,7 +1059,7 @@ body: hello world)$ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; content_by_lua return; diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 431d5cf38d..054f820528 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -128,7 +128,7 @@ del timer 1234 end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.say("hello, world!") diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 150ed23b7c..69b032b26b 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -591,7 +591,7 @@ lua tcp socket write timed out end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() diff --git a/t/093-uthread.t b/t/093-uthread.t index 4b809ffe27..403c79ca77 100644 --- a/t/093-uthread.t +++ b/t/093-uthread.t @@ -29,7 +29,7 @@ __DATA__ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -65,11 +65,11 @@ after end ngx.say("before 1") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after 1") ngx.say("before 2") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after 2") '; } @@ -109,7 +109,7 @@ after 2 end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") '; } @@ -150,11 +150,11 @@ after sleep end ngx.say("1: before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("1: after thread create") ngx.say("2: before thread create") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("2: after thread create") '; } @@ -193,7 +193,7 @@ delete thread 2 ngx.blah() end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -225,7 +225,7 @@ lua thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") '; } @@ -269,7 +269,7 @@ after capture: hello world end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) @@ -320,7 +320,7 @@ after capture: hello foo end ngx.say("before thread create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread create") local res = ngx.location.capture("/proxy?bar") ngx.say("capture: ", res.body) @@ -378,11 +378,11 @@ capture: hello bar end ngx.say("before thread 1 create") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after thread 1 create") ngx.say("before thread 2 create") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after thread 2 create") local res = ngx.location.capture("/proxy?bar") @@ -442,7 +442,7 @@ g: after capture: hello bah content_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -451,7 +451,7 @@ g: after capture: hello bah end ngx.say("before f") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after f") '; } @@ -485,7 +485,7 @@ after g content_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -495,7 +495,7 @@ after g end ngx.say("before f") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after f") '; } @@ -533,7 +533,7 @@ hello in g() ngx.sleep(0.1) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; } @@ -563,7 +563,7 @@ status: running co = coroutine.running() end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; } @@ -599,7 +599,7 @@ status: dead ngx.sleep(0.1) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("status: ", coroutine.status(co)) '; } @@ -627,7 +627,7 @@ status: normal content_by_lua ' function f() ngx.say("before g") - ngx.thread.create(g) + ngx.thread.spawn(g) ngx.say("after g") end @@ -682,7 +682,7 @@ after f ngx.say("0") yield(self) ngx.say("1") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("2") yield(self) ngx.say("3") @@ -738,8 +738,8 @@ f 3 ngx.say("g 3") end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) ngx.say("done") '; } @@ -780,7 +780,7 @@ g 3 end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.flush(true) '; @@ -818,8 +818,8 @@ after ngx.flush(true) end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) '; } --- request @@ -876,7 +876,7 @@ hello from g end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -922,7 +922,7 @@ received: OK end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -959,7 +959,7 @@ received: hello udp end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -1005,7 +1005,7 @@ body: hello world)$ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index cfb8377fa6..507e891582 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -31,7 +31,7 @@ __DATA__ end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.sleep(1) ngx.say("end") @@ -94,7 +94,7 @@ hello in thread end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.sleep(1) ngx.say("end") @@ -181,8 +181,8 @@ after ngx.say("g") end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) ngx.say("end") '; } @@ -265,7 +265,7 @@ f end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") '; } @@ -301,7 +301,7 @@ exiting the user thread end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() local ok, err = sock:connect("www.google.com", 80) @@ -396,7 +396,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() local ok, err = sock:setpeername("www.google.com", 80) @@ -489,7 +489,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) @@ -578,7 +578,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() @@ -677,7 +677,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() @@ -782,7 +782,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() @@ -875,7 +875,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") local sock = ngx.req.socket() @@ -963,7 +963,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.req.read_body() @@ -1046,7 +1046,7 @@ after end ngx.say("before") - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.say("after") ngx.location.capture("/sleep") @@ -1126,7 +1126,7 @@ attempt to abort with pending subrequests ngx.exit(0) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture("/sleep") ngx.say("end") @@ -1209,7 +1209,7 @@ attempt to abort with pending subrequests ngx.exit(0) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture_multi{ {"/echo"}, diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 7311047d22..8016a13dce 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -28,7 +28,7 @@ __DATA__ ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) ngx.say("hello") '; @@ -63,7 +63,7 @@ i am foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) '; } @@ -96,7 +96,7 @@ i am foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) '; } @@ -181,8 +181,8 @@ hello foo ngx.sleep(1) end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) '; } @@ -266,7 +266,7 @@ hello foo ngx.exec("/foo") end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture("/sleep") ngx.say("end") diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index ebdea7d8e4..794578055e 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -31,7 +31,7 @@ __DATA__ ngx.redirect(301) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture_multi{ {"/echo"}, @@ -120,7 +120,7 @@ attempt to abort with pending subrequests ngx.redirect(301) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) ngx.say("end") '; diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t index addc29885f..bbfc748d8d 100644 --- a/t/097-uthread-rewrite.t +++ b/t/097-uthread-rewrite.t @@ -28,7 +28,7 @@ __DATA__ ngx.req.set_uri("/foo", true) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) ngx.say("hello") '; @@ -63,7 +63,7 @@ i am foo ngx.req.set_uri("/foo", true) end - ngx.thread.create(f) + ngx.thread.spawn(f) '; } @@ -96,7 +96,7 @@ i am foo ngx.req.set_uri("/foo", true) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.sleep(1) '; } @@ -181,8 +181,8 @@ hello foo ngx.sleep(1) end - ngx.thread.create(f) - ngx.thread.create(g) + ngx.thread.spawn(f) + ngx.thread.spawn(g) '; } @@ -266,7 +266,7 @@ hello foo ngx.req.set_uri("/foo", true) end - ngx.thread.create(f) + ngx.thread.spawn(f) ngx.location.capture("/sleep") ngx.say("end") From 00e99d519fb5856c066f6a8a52e5a924a251af48 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Sep 2012 17:20:27 -0700 Subject: [PATCH 0100/2239] bugfix: the ngx.thread API did not work in access_by_lua*. --- src/ngx_http_lua_accessby.c | 27 +- t/024-access/uthread-exec.t | 343 ++++++++ t/024-access/uthread-exit.t | 1316 +++++++++++++++++++++++++++++++ t/024-access/uthread-redirect.t | 191 +++++ t/024-access/uthread.t | 1091 +++++++++++++++++++++++++ 5 files changed, 2961 insertions(+), 7 deletions(-) create mode 100644 t/024-access/uthread-exec.t create mode 100644 t/024-access/uthread-exit.t create mode 100644 t/024-access/uthread-redirect.t create mode 100644 t/024-access/uthread.t diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 4f7d7545ac..5fb2094d9f 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -88,11 +88,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) dd("entered? %d", (int) ctx->entered_access_phase); - if (ctx->waiting_more_body) { - dd("WAITING MORE BODY"); - return NGX_DONE; - } - if (ctx->entered_access_phase) { dd("calling wev handler"); rc = ctx->resume_handler(r); @@ -105,6 +100,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) return NGX_DECLINED; } + if (ctx->waiting_more_body) { + dd("WAITING MORE BODY"); + return NGX_DONE; + } + if (llcf->force_read_body && !ctx->read_body_done) { r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; @@ -291,12 +291,25 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + + if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + return rc; + } + + return NGX_DECLINED; } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, L, r, ctx); + + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + + if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { + return rc; + } + + return NGX_DECLINED; } return NGX_DECLINED; diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t new file mode 100644 index 0000000000..669839bf7f --- /dev/null +++ b/t/024-access/uthread-exec.t @@ -0,0 +1,343 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: exec in user thread (entry still pending) +--- config + location /lua { + access_by_lua ' + function f() + ngx.exec("/foo") + end + + ngx.thread.spawn(f) + ngx.sleep(1) + ngx.say("hello") + '; + content_by_lua return; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 2: exec in user thread (entry already quits) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.spawn(f) + '; + content_by_lua return; + } + + location /foo { + echo i am foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 + +--- response_body +i am foo +--- no_error_log +[error] + + + +=== TEST 3: exec in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.spawn(f) + ngx.sleep(1) + '; + content_by_lua return; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 4: exec in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + function g() + ngx.sleep(1) + end + + ngx.thread.spawn(f) + ngx.thread.spawn(g) + '; + content_by_lua return; + } + + location = /foo { + echo hello foo; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +free request + +--- response_body +hello foo +--- no_error_log +[error] + + + +=== TEST 5: exec in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exec("/foo") + end + + ngx.thread.spawn(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } + + location = /foo { + echo hello world; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t new file mode 100644 index 0000000000..260318f1e8 --- /dev/null +++ b/t/024-access/uthread-exit.t @@ -0,0 +1,1316 @@ +# 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; + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: exit in user thread (entry thread is still pending to run) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +M(timer-add) { + if ($arg2 == 1000) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 1000) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 1000) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before +hello in thread +--- no_error_log +[error] + + + +=== TEST 2: exit in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 3: exit in a user thread (another user thread is still pending on ngx.sleep) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f") + ngx.exit(0) + end + + function g() + ngx.sleep(1) + ngx.say("g") + end + + ngx.thread.spawn(f) + ngx.thread.spawn(g) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +create 3 in 1 +create user thread 3 in 1 +add timer 1000 +delete thread 1 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 3 +delete thread 4 +free request + +--- response_body +end +f +--- no_error_log +[error] + + + +=== TEST 4: exit in user thread (entry already quits) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("exiting the user thread") + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +after +exiting the user thread +--- no_error_log +[error] + + + +=== TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_resolve_cleanup) { + println("lua tcp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua tcp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) +--- config + location /lua { + resolver www.google.com; + resolver_timeout 12s; + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +F(ngx_resolve_name) { + printf("resolving %s\n", user_string_n($ctx->name->data, $ctx->name->len)) +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_resolve_cleanup) { + println("lua udp resolve cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +resolving www.google.com +add timer 12000 +expire timer 100 +lua udp resolve cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 7: exit in user thread (entry thread is still pending on tcpsock:connect) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.tcp() + sock:settimeout(12000) + local ok, err = sock:connect("8.8.4.4", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } + /* + if (tm == 12000) { + print_ubacktrace() + } + */ +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 8: exit in user thread (entry thread is still pending on tcpsock:receive) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 9: exit in user thread (entry thread is still pending on tcpsock:receiveuntil's iterator) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.tcp() + + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local bytes, ok = sock:send("blpop not_exists 2\\r\\n") + if not bytes then + ngx.say("failed to send: ", err) + return + end + + local it, err = sock:receiveuntil("\\r\\n") + if not it then + ngx.say("failed to receive until: ", err) + return + end + + sock:settimeout(12000) + + local data, err = it() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 10: exit in user thread (entry thread is still pending on udpsock:receive) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.socket.udp() + + local ok, err = sock:setpeername("8.8.8.8", 12345) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + sock:settimeout(12000) + + local data, err = sock:receive() + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_udp_socket_cleanup) { + println("lua udp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua udp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 11: exit in user thread (entry thread is still pending on reqsock:receive) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + local sock = ngx.req.socket() + + sock:settimeout(12000) + + local data, err = sock:receive(1024) + if not data then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("end") + '; + content_by_lua return; + } +--- request +POST /lua +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_tcp_socket_cleanup) { + println("lua tcp socket cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua tcp socket cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 12: exit in user thread (entry thread is still pending on ngx.req.read_body) +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + + ngx.req.read_body() + + ngx.say("end") + '; + content_by_lua return; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 12000 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 12000 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_req_body_cleanup) { + println("lua req body cleanup") +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 12000 +expire timer 100 +lua req body cleanup +delete timer 12000 +delete thread 2 +delete thread 1 +delete thread 3 +free request + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 13: exit in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 14: exit in user thread (entry thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.spawn(f) + + ngx.location.capture("/sleep") + ngx.say("end") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} + +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 15: exit in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.exit(0) + end + + ngx.thread.spawn(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + content_by_lua return; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t new file mode 100644 index 0000000000..199d158c87 --- /dev/null +++ b/t/024-access/uthread-redirect.t @@ -0,0 +1,191 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ngx.redirect() in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.spawn(f) + + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + '; + content_by_lua return; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +create user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + + + +=== TEST 2: redirect in user thread (entry thread is still pending on ngx.sleep) +--- config + location /lua { + access_by_lua ' + function f() + ngx.sleep(0.1) + ngx.redirect(301) + end + + ngx.thread.spawn(f) + ngx.sleep(1) + ngx.say("end") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- 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 user thread 2 in 1 +add timer 100 +add timer 1000 +expire timer 100 +lua sleep cleanup +delete timer 1000 +delete thread 2 +delete thread 1 +free request + +--- response_body_like: 302 Found +--- error_code: 302 +--- no_error_log +[error] + diff --git a/t/024-access/uthread.t b/t/024-access/uthread.t new file mode 100644 index 0000000000..633a4062d6 --- /dev/null +++ b/t/024-access/uthread.t @@ -0,0 +1,1091 @@ +# 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; + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 1); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: simple user thread without I/O +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval +<<'_EOC_' . $::StapScript; + +F(ngx_http_lua_send_chain_link) { + printf("send link %p\n", $in) +} + +F(ngx_http_core_content_phase) { + println("core content phase") +} + +_EOC_ +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 2: two simple user threads without I/O +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("in thread 1") + end + + function g() + ngx.say("in thread 2") + end + + ngx.say("before 1") + ngx.thread.spawn(f) + ngx.say("after 1") + + ngx.say("before 2") + ngx.thread.spawn(g) + ngx.say("after 2") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +create 3 in 1 +create user thread 3 in 1 +delete thread 3 +delete thread 1 +delete thread 4 + +--- response_body +before 1 +in thread 1 +after 1 +before 2 +in thread 2 +after 2 +--- no_error_log +[error] + + + +=== TEST 3: simple user thread with sleep +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before sleep") + ngx.sleep(0.1) + ngx.say("after sleep") + end + + ngx.say("before thread create") + ngx.thread.spawn(f) + ngx.say("after thread create") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before sleep +after thread create +after sleep +--- no_error_log +[error] + + + +=== TEST 4: two simple user threads with sleep +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("1: before sleep") + ngx.sleep(0.2) + ngx.say("1: after sleep") + end + + function g() + ngx.say("2: before sleep") + ngx.sleep(0.1) + ngx.say("2: after sleep") + end + + ngx.say("1: before thread create") + ngx.thread.spawn(f) + ngx.say("1: after thread create") + + ngx.say("2: before thread create") + ngx.thread.spawn(g) + ngx.say("2: after thread create") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 3 +delete thread 2 +delete thread 4 + +--- response_body +1: before thread create +1: before sleep +1: after thread create +2: before thread create +2: before sleep +2: after thread create +2: after sleep +1: after sleep +--- no_error_log +[error] + + + +=== TEST 5: error in user thread +--- config + location /lua { + access_by_lua ' + function f() + ngx.blah() + end + + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +lua thread aborted: runtime error: [string "access_by_lua"]:3: attempt to call field 'blah' (a nil value) + + + +=== TEST 6: simple user threads doing a single subrequest (entry quits early) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before capture") + res = ngx.location.capture("/proxy") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.spawn(f) + ngx.say("after thread create") + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/foo; + } + + location /foo { + echo_sleep 0.1; + echo -n hello world; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +after capture: hello world +--- no_error_log +[error] + + + +=== TEST 7: simple user threads doing a single subrequest (entry also does a subrequest and quits early) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.spawn(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +capture: hello bar +after capture: hello foo +--- no_error_log +[error] + + + +=== TEST 8: simple user threads doing a single subrequest (entry also does a subrequest and quits late) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("after capture: ", res.body) + end + + ngx.say("before thread create") + ngx.thread.spawn(f) + ngx.say("after thread create") + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +before thread create +before capture +after thread create +after capture: hello foo +capture: hello bar +--- no_error_log +[error] + + + +=== TEST 9: two simple user threads doing single subrequests (entry also does a subrequest and quits between) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("f: before capture") + local res = ngx.location.capture("/proxy?foo") + ngx.say("f: after capture: ", res.body) + end + + function g() + ngx.say("g: before capture") + local res = ngx.location.capture("/proxy?bah") + ngx.say("g: after capture: ", res.body) + end + + ngx.say("before thread 1 create") + ngx.thread.spawn(f) + ngx.say("after thread 1 create") + + ngx.say("before thread 2 create") + ngx.thread.spawn(g) + ngx.say("after thread 2 create") + + local res = ngx.location.capture("/proxy?bar") + ngx.say("capture: ", res.body) + '; + content_by_lua return; + } + + location /proxy { + proxy_pass http://127.0.0.1:$server_port/$args; + } + + location /foo { + echo_sleep 0.1; + echo -n hello foo; + } + + location /bar { + echo_sleep 0.2; + echo -n hello bar; + } + + location /bah { + echo_sleep 0.3; + echo -n hello bah; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 2 +delete thread 1 +delete thread 3 +delete thread 4 + +--- response_body +before thread 1 create +f: before capture +after thread 1 create +before thread 2 create +g: before capture +after thread 2 create +f: after capture: hello foo +capture: hello bar +g: after capture: hello bah +--- no_error_log +[error] + + + +=== TEST 10: nested user threads +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before g") + ngx.thread.spawn(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.spawn(f) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 3 +delete thread 1 +delete thread 2 +delete thread 4 + +--- response_body +before f +before g +hello in g() +after f +after g +--- no_error_log +[error] + + + +=== TEST 11: nested user threads (with I/O) +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before g") + ngx.thread.spawn(g) + ngx.say("after g") + end + + function g() + ngx.sleep(0.1) + ngx.say("hello in g()") + end + + ngx.say("before f") + ngx.thread.spawn(f) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 1 +delete thread 2 +delete thread 3 +delete thread 4 + +--- response_body +before f +before g +after f +after g +hello in g() +--- no_error_log +[error] + + + +=== TEST 12: coroutine status of a running user thread +--- config + location /lua { + access_by_lua ' + local co + function f() + co = coroutine.running() + ngx.sleep(0.1) + end + + ngx.thread.spawn(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +status: running +--- no_error_log +[error] + + + +=== TEST 13: coroutine status of a dead user thread +--- config + location /lua { + access_by_lua ' + local co + function f() + co = coroutine.running() + end + + ngx.thread.spawn(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +status: dead +--- no_error_log +[error] + + + +=== TEST 14: coroutine status of a "normal" user thread +--- config + location /lua { + access_by_lua ' + local co + function f() + co = coroutine.running() + local co2 = coroutine.create(g) + coroutine.resume(co2) + end + + function g() + ngx.sleep(0.1) + end + + ngx.thread.spawn(f) + ngx.say("status: ", coroutine.status(co)) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 2 +delete thread 1 +delete thread 2 +delete thread 4 + +--- response_body +status: normal +--- no_error_log +[error] + + + +=== TEST 15: creating user threads in a user coroutine +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("before g") + ngx.thread.spawn(g) + ngx.say("after g") + end + + function g() + ngx.say("hello in g()") + end + + ngx.say("before f") + local co = coroutine.create(f) + coroutine.resume(co) + ngx.say("after f") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +create user thread 3 in 2 +delete thread 3 +delete thread 1 +delete thread 4 + +--- response_body +before f +before g +hello in g() +after g +after f +--- no_error_log +[error] + + + +=== TEST 16: manual time slicing between a user thread and the entry thread +--- config + location /lua { + access_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + ngx.say("1") + ngx.thread.spawn(f) + ngx.say("2") + yield(self) + ngx.say("3") + yield(self) + ngx.say("4") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1 +delete thread 3 + +--- response_body +0 +1 +f 1 +2 +f 2 +3 +f 3 +4 +--- no_error_log +[error] + + + +=== TEST 17: manual time slicing between two user threads +--- config + location /lua { + access_by_lua ' + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + function g() + local self = coroutine.running() + ngx.say("g 1") + yield(self) + ngx.say("g 2") + yield(self) + ngx.say("g 3") + end + + ngx.thread.spawn(f) + ngx.thread.spawn(g) + ngx.say("done") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3 +delete thread 4 + +--- response_body +f 1 +g 1 +f 2 +done +g 2 +f 3 +g 3 +--- no_error_log +[error] + + + +=== TEST 18: entry thread and a user thread flushing at the same time +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello in thread") + coroutine.yield(coroutine.running) + ngx.flush(true) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + ngx.flush(true) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +hello in thread +after +--- no_error_log +[error] + + + +=== TEST 19: two user threads flushing at the same time +--- config + location /lua { + access_by_lua ' + function f() + ngx.say("hello from f") + ngx.flush(true) + end + + function g() + ngx.say("hello from g") + ngx.flush(true) + end + + ngx.thread.spawn(f) + ngx.thread.spawn(g) + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:create 2 in 1 +create user thread 2 in 1 +create 3 in 1 +create user thread 3 in 1 +delete thread 1 +delete thread 2 +delete thread 3|create 2 in 1 +create user thread 2 in 1 +delete thread 2 +create 3 in 1 +create user thread 3 in 1 +delete thread 3 +delete thread 1) +delete thread 4$ + +--- response_body +hello from f +hello from g +--- no_error_log +[error] + + + +=== TEST 20: user threads + ngx.socket.tcp +--- config + location /lua { + access_by_lua ' + function f() + 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 + local bytes, err = sock:send("flush_all\\r\\n") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- response_body +before +after +received: OK +--- no_error_log +[error] + + + +=== TEST 21: user threads + ngx.socket.udp +--- config + location /lua { + access_by_lua ' + function f() + local sock = ngx.socket.udp() + local ok, err = sock:setpeername("127.0.0.1", 12345) + local bytes, err = sock:send("blah") + if not bytes then + ngx.say("failed to send query: ", err) + return + end + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive: ", err) + return + end + + ngx.say("received: ", line) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2 +delete thread 3 + +--- udp_listen: 12345 +--- udp_query: blah +--- udp_reply: hello udp +--- response_body +before +after +received: hello udp +--- no_error_log +[error] + + + +=== TEST 22: simple user thread with ngx.req.read_body() +--- config + location /lua { + access_by_lua ' + function f() + ngx.req.read_body() + local body = ngx.req.get_body_data() + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2) +delete thread 3$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + + + +=== TEST 23: simple user thread with ngx.req.socket() +--- config + location /lua { + access_by_lua ' + function f() + local sock = ngx.req.socket() + local body, err = sock:receive(11) + if not body then + ngx.say("failed to read body: ", err) + return + end + + ngx.say("body: ", body) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + '; + content_by_lua return; + } +--- request +POST /lua +hello world +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^(?:create 2 in 1 +create user thread 2 in 1 +delete thread 2 +delete thread 1|create 2 in 1 +create user thread 2 in 1 +delete thread 1 +delete thread 2) +delete thread 3$ + +--- response_body_like chop +^(?:before +body: hello world +after|before +after +body: hello world)$ + +--- no_error_log +[error] + From 15d8550b6f25754f48ce1f30d28ed7bf08a6c6da Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 26 Sep 2012 15:40:28 -0700 Subject: [PATCH 0101/2239] minor coding style fixes in the lua/luajit bytecode loader. --- src/ngx_http_lua_clfactory.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 7465e2bdaf..8e30d6fbe5 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -656,7 +656,8 @@ ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, ls.s = buff; ls.size = size; - ls.sent_begin = ls.sent_end = 0; + ls.sent_begin = 0; + ls.sent_end = 0; return lua_load(L, clfactory_getS, &ls, name); } @@ -758,9 +759,7 @@ clfactory_errfile(lua_State *L, const char *what, int fname_index) static const char * clfactory_getS(lua_State *L, void *ud, size_t *size) { - clfactory_buffer_ctx_t *ls; - - ls = (clfactory_buffer_ctx_t *) ud; + clfactory_buffer_ctx_t *ls = ud; if (ls->sent_begin == 0) { ls->sent_begin = 1; From 0b6685c20c8ac2c525b1640cb1993486952d3a18 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 26 Sep 2012 22:10:30 -0700 Subject: [PATCH 0102/2239] bumped version to 0.6.7. --- README | 6 +++--- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index 5140fa0de8..12b3f1e5ef 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.6.6 - () released on 20 + This document describes ngx_lua v0.6.7 + () released on 26 September 2012. Synopsis @@ -5075,7 +5075,7 @@ Typical Uses Nginx Compatibility The module is compatible with the following versions of Nginx: - * 1.3.x (last tested: 1.3.4) + * 1.3.x (last tested: 1.3.6) * 1.2.x (last tested: 1.2.3) diff --git a/README.markdown b/README.markdown index a1b158a3e1..6789ea6566 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.6.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 September 2012. +This document describes ngx_lua [v0.6.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 26 September 2012. Synopsis ======== @@ -4511,7 +4511,7 @@ Nginx Compatibility =================== The module is compatible with the following versions of Nginx: -* 1.3.x (last tested: 1.3.4) +* 1.3.x (last tested: 1.3.6) * 1.2.x (last tested: 1.2.3) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a292b92247..c470a1da49 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.6.6] released on 20 September 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.7] released on 26 September 2012. = Synopsis = @@ -4352,7 +4352,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The module is compatible with the following versions of Nginx: -* 1.3.x (last tested: 1.3.4) +* 1.3.x (last tested: 1.3.6) * 1.2.x (last tested: 1.2.3) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) From ad5e7f7c3b7dcfb250c81a5e8294d363fe121aff Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 00:00:18 -0700 Subject: [PATCH 0103/2239] bugfix: ngx.re.gmatch might loop infinitely when the pattern matches an empty string. thanks Lance Li and xingxing for tracking this issue down. --- src/ngx_http_lua_regex.c | 6 +++++- t/035-gmatch.t | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 137f203b0e..fb7d5868a9 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -944,7 +944,11 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) } offset = cap[1]; - if (offset == (ssize_t) subj.len) { + if (offset == cap[0]) { + offset++; + } + + if (offset >= (ssize_t) subj.len) { offset = -1; if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) { diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 56c3822ce4..9b669c67b2 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -486,3 +486,27 @@ sr failed: 500 --- error_log attempt to use ngx.re.gmatch iterator in a request that did not create it + + +=== TEST 20: gmatch (empty matched string) +--- config + location /re { + content_by_lua ' + for m in ngx.re.gmatch("hello", "a|") do + if m then + ngx.say("matched: [", m[0], "]") + else + ngx.say("not matched: ", m) + end + end + '; + } +--- request + GET /re +--- response_body +matched: [] +matched: [] +matched: [] +matched: [] +matched: [] + From 4b9100c1dd9c3634da80f68fcdbcd39961b903df Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 00:07:47 -0700 Subject: [PATCH 0104/2239] bugfix: pattern matching an empty substring in ngx.re.gmatch did not match at the end of the subject string. --- src/ngx_http_lua_regex.c | 2 +- t/035-gmatch.t | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index fb7d5868a9..aeb822b6db 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -948,7 +948,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) offset++; } - if (offset >= (ssize_t) subj.len) { + if (offset > (ssize_t) subj.len) { offset = -1; if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) { diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 9b669c67b2..02d1723959 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -509,4 +509,5 @@ matched: [] matched: [] matched: [] matched: [] +matched: [] From d37c193a933c336264fdb30b9d86a5822cc7e413 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 11:38:56 -0700 Subject: [PATCH 0105/2239] bugfix: ngx.re.gsub might enter infinet loops because it could not handle patterns matching emptry strings properly. bugfix: ngx.re.gsub incorrectly skipped matching altogether when the subject string was empty. --- src/ngx_http_lua_regex.c | 32 +++++++++++------ t/037-gsub.t | 78 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index aeb822b6db..494d6649d7 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1087,6 +1087,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) int type; unsigned func; int offset; + int cp_offset; size_t count; luaL_Buffer luabuf; ngx_int_t flags; @@ -1439,12 +1440,9 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) exec: count = 0; offset = 0; + cp_offset = 0; for (;;) { - if (subj.len == 0) { - break; - } - if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA @@ -1531,14 +1529,21 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) return luaL_argerror(L, 3, msg); } - luaL_addlstring(&luabuf, (char *) &subj.data[offset], - cap[0] - offset); + luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], + cap[0] - cp_offset); luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); lua_pop(L, 1); - offset = cap[1]; + cp_offset = cap[1]; + offset = cp_offset; + if (offset == cap[0]) { + offset++; + if (offset > (ssize_t) subj.len) { + break; + } + } if (global) { continue; @@ -1547,7 +1552,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) break; } - rc = ngx_http_lua_complex_value(r, &subj, offset, rc, cap, ctpl, + rc = ngx_http_lua_complex_value(r, &subj, cp_offset, rc, cap, ctpl, &luabuf); if (rc != NGX_OK) { @@ -1556,7 +1561,14 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) goto error; } - offset = cap[1]; + cp_offset = cap[1]; + offset = cp_offset; + if (offset == cap[0]) { + offset++; + if (offset > (ssize_t) subj.len) { + break; + } + } if (global) { continue; @@ -1570,7 +1582,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) lua_settop(L, 1); } else { - if (offset != (int) subj.len) { + if (offset < (int) subj.len) { dd("adding trailer: %s (len %d)", &subj.data[offset], (int) (subj.len - offset)); diff --git a/t/037-gsub.t b/t/037-gsub.t index 47e0dcd4a1..cbc6ab2101 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); +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); no_long_string(); @@ -179,3 +179,79 @@ hello, world {foohbarhbaz} 2 + + +=== TEST 10: gsub with a patch matching an empty substring (string template) +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("hello", "a|", "b") + ngx.say("s: ", s) + ngx.say("n: ", n) + '; + } +--- request + GET /re +--- response_body +s: bhbeblblbob +n: 6 +--- no_error_log +[error] + + + +=== TEST 11: gsub with a patch matching an empty substring (string template, empty subj) +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("", "a|", "b") + ngx.say("s: ", s) + ngx.say("n: ", n) + '; + } +--- request + GET /re +--- response_body +s: b +n: 1 +--- no_error_log +[error] + + + +=== TEST 12: gsub with a patch matching an empty substring (func) +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("hello", "a|", function () return "b" end) + ngx.say("s: ", s) + ngx.say("n: ", n) + '; + } +--- request + GET /re +--- response_body +s: bhbeblblbob +n: 6 +--- no_error_log +[error] + + + +=== TEST 13: gsub with a patch matching an empty substring (func, empty subj) +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.gsub("", "a|", function () return "b" end) + ngx.say("s: ", s) + ngx.say("n: ", n) + '; + } +--- request + GET /re +--- response_body +s: b +n: 1 +--- no_error_log +[error] + From 1ff7288eb22754a926c95529c0c6c8720a8b0b2c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 11:49:23 -0700 Subject: [PATCH 0106/2239] added a (passing) test for empty pattern in ng.re.match. --- t/034-match.t | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/t/034-match.t b/t/034-match.t index 96d95b498d..3883aa870a 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 + 4); +plan tests => repeat_each() * (blocks() * 2 + 5); #no_diff(); no_long_string(); @@ -702,3 +702,27 @@ done --- response_body done + + +=== TEST 34: non-empty subject, empty pattern +--- config + location /re { + content_by_lua ' + local ctx = {} + local m = ngx.re.match("hello, 1234", "", "", ctx) + if m then + ngx.say("pos: ", ctx.pos) + ngx.say("m: ", m[0]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +pos: 0 +m: +--- no_error_log +[error] + From b051763cc0abe4f86c160317f2e510fe913deecd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 15:05:48 -0700 Subject: [PATCH 0107/2239] refactor: renamed t/*uthread.t to t/*uthread-spawn.t. --- t/023-rewrite/{uthread.t => uthread-spawn.t} | 0 t/024-access/{uthread.t => uthread-spawn.t} | 0 t/{093-uthread.t => 093-uthread-spawn.t} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename t/023-rewrite/{uthread.t => uthread-spawn.t} (100%) rename t/024-access/{uthread.t => uthread-spawn.t} (100%) rename t/{093-uthread.t => 093-uthread-spawn.t} (100%) diff --git a/t/023-rewrite/uthread.t b/t/023-rewrite/uthread-spawn.t similarity index 100% rename from t/023-rewrite/uthread.t rename to t/023-rewrite/uthread-spawn.t diff --git a/t/024-access/uthread.t b/t/024-access/uthread-spawn.t similarity index 100% rename from t/024-access/uthread.t rename to t/024-access/uthread-spawn.t diff --git a/t/093-uthread.t b/t/093-uthread-spawn.t similarity index 100% rename from t/093-uthread.t rename to t/093-uthread-spawn.t From 171de5a7c363602edc4eecdeb58416af48c937b6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 15:17:53 -0700 Subject: [PATCH 0108/2239] refactor: renamed ngx_http_lua_uthread_create to ngx_http_lua_uthread_spawn for consistency with the Lua API name. --- 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 f664a2ae58..9f0d9ab282 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -10,7 +10,7 @@ #include "ngx_http_lua_probe.h" -static int ngx_http_lua_uthread_create(lua_State *L); +static int ngx_http_lua_uthread_spawn(lua_State *L); void @@ -19,7 +19,7 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) /* new thread table */ lua_newtable(L); - lua_pushcfunction(L, ngx_http_lua_uthread_create); + lua_pushcfunction(L, ngx_http_lua_uthread_spawn); lua_setfield(L, -2, "spawn"); lua_setfield(L, -2, "thread"); @@ -27,7 +27,7 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) static int -ngx_http_lua_uthread_create(lua_State *L) +ngx_http_lua_uthread_spawn(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; From 97f4474a95aa9adce17ce64a3d0d9d2e6f93338e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Sep 2012 20:33:38 -0700 Subject: [PATCH 0109/2239] bumped version to 0.6.8. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 12b3f1e5ef..73643fcddf 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.6.7 - () released on 26 + This document describes ngx_lua v0.6.8 + () released on 28 September 2012. Synopsis diff --git a/README.markdown b/README.markdown index 6789ea6566..9f2e65532c 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.6.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 26 September 2012. +This document describes ngx_lua [v0.6.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 28 September 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index c470a1da49..7a0e5c015e 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.6.7] released on 26 September 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.8] released on 28 September 2012. = Synopsis = From 5d5edcf02809f150fb0473422b86be3ba82b2a26 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 29 Sep 2012 23:47:19 -0700 Subject: [PATCH 0110/2239] feature: implemented ngx.thread.wait() for synchronously waiting on a child user thread, which also returns the final results of the last implicit call of coroutine.resume() on the user thread coroutine. so now an non-captured Lua exception in a user thread will not abort other running threads in the same nginx request. --- dtrace/ngx_lua_provider.d | 5 +- src/ngx_http_lua_common.h | 14 +- src/ngx_http_lua_coroutine.c | 7 +- src/ngx_http_lua_probe.h | 10 +- src/ngx_http_lua_uri.c | 39 +- src/ngx_http_lua_uthread.c | 89 ++++- src/ngx_http_lua_uthread.h | 7 +- src/ngx_http_lua_util.c | 224 ++++++++++-- src/ngx_http_lua_util.h | 3 + t/023-rewrite/uthread-exec.t | 30 +- t/023-rewrite/uthread-exit.t | 101 ++++-- t/023-rewrite/uthread-redirect.t | 18 +- t/023-rewrite/uthread-spawn.t | 170 ++++++--- t/024-access/uthread-exec.t | 30 +- t/024-access/uthread-exit.t | 101 ++++-- t/024-access/uthread-redirect.t | 18 +- t/024-access/uthread-spawn.t | 170 ++++++--- t/034-match.t | 2 +- t/044-req-body.t | 2 +- t/057-flush-timeout.t | 3 +- t/065-tcp-socket-timeout.t | 3 +- t/073-backtrace.t | 2 +- t/093-uthread-spawn.t | 144 +++++--- t/094-uthread-exit.t | 153 ++++++-- t/095-uthread-exec.t | 101 +++++- t/096-uthread-redirect.t | 107 +++++- t/097-uthread-rewrite.t | 37 +- t/098-uthread-wait.t | 586 +++++++++++++++++++++++++++++++ t/StapThread.pm | 26 +- 29 files changed, 1863 insertions(+), 339 deletions(-) create mode 100644 t/098-uthread-wait.t diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index b20a8ba213..aa23e6fe7f 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -35,7 +35,7 @@ provider nginx_lua { ngx_http_request_t *r, void *u, u_char *data, size_t len); /* lua_State *creator, lua_State *newthread */ - probe http__lua__user__thread__create(ngx_http_request_t *r, + probe http__lua__user__thread__spawn(ngx_http_request_t *r, void *creator, void *newthread); /* lua_State *thread, ngx_http_lua_ctx_t *ctx */ @@ -44,6 +44,9 @@ provider nginx_lua { /* lua_State *thread */ probe http__lua__run__posted__thread(ngx_http_request_t *r, void *thread, int status); + + probe http__lua__coroutine__done(ngx_http_request_t *r, void *co, + int success); }; diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 2d81b21fbb..0c28c05e3c 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -201,7 +201,8 @@ typedef enum { NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */ NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */ NGX_HTTP_LUA_CO_NORMAL = 2, /* coroutine normal */ - NGX_HTTP_LUA_CO_DEAD = 3 /* coroutine dead */ + NGX_HTTP_LUA_CO_DEAD = 3, /* coroutine dead */ + NGX_HTTP_LUA_CO_ZOMBIE = 4, /* coroutine zombie */ } ngx_http_lua_co_status_t; @@ -221,6 +222,8 @@ struct ngx_http_lua_co_ctx_s { lua_State *co; ngx_http_lua_co_ctx_t *parent_co_ctx; + ngx_http_lua_posted_thread_t *zombie_child_threads; + ngx_http_cleanup_pt cleanup; unsigned nsubreqs; /* number of subrequests of the @@ -244,7 +247,10 @@ struct ngx_http_lua_co_ctx_s { from beging collected by the Lua GC */ - ngx_http_lua_co_status_t co_status:2; /* the current coroutine's status */ + 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 flushing:1; /* indicates whether the current coroutine is waiting for @@ -252,6 +258,10 @@ struct ngx_http_lua_co_ctx_s { unsigned is_uthread:1; /* whether the current coroutine is a user thread */ + + unsigned thread_spawn_yielded:1; /* yielded from + the ngx.thread.spawn() + call */ }; diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 23a7d86d80..a30c92cc70 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -23,8 +23,9 @@ static int ngx_http_lua_coroutine_yield(lua_State *L); static int ngx_http_lua_coroutine_status(lua_State *L); -static const char * ngx_http_lua_co_status_names[] = - {"running", "suspended", "normal", "dead"}; +static const char * + ngx_http_lua_co_status_names[] = + {"running", "suspended", "normal", "dead", "zombie"}; @@ -211,7 +212,7 @@ ngx_http_lua_coroutine_yield(lua_State *L) ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD; - if (coctx->parent_co_ctx) { + if (!coctx->is_uthread && coctx->parent_co_ctx) { dd("set coroutine to running"); coctx->parent_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index aaf31d37db..df5b632cab 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -47,8 +47,8 @@ #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len)\ NGINX_LUA_HTTP_LUA_SOCKET_TCP_SETKEEPALIVE_BUF_UNREAD(r, u, data, len) -#define ngx_http_lua_probe_user_thread_create(r, creator, newthread) \ - NGINX_LUA_HTTP_LUA_USER_THREAD_CREATE(r, creator, newthread) +#define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread) \ + NGINX_LUA_HTTP_LUA_USER_THREAD_SPAWN(r, creator, newthread) #define ngx_http_lua_probe_thread_delete(r, thread, ctx) \ NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread, ctx) @@ -56,6 +56,9 @@ #define ngx_http_lua_probe_run_posted_thread(r, thread, status) \ NGINX_LUA_HTTP_LUA_RUN_POSTED_THREAD(r, thread, status) +#define ngx_http_lua_probe_coroutine_done(r, co, success) \ + NGINX_LUA_HTTP_LUA_COROUTINE_DONE(r, co, success) + #else /* !(NGX_DTRACE) */ #define ngx_http_lua_probe_info(s) @@ -68,9 +71,10 @@ #define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) #define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len) -#define ngx_http_lua_probe_user_thread_create(r, creator, newthread) +#define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread) #define ngx_http_lua_probe_thread_delete(r, thread, ctx) #define ngx_http_lua_probe_run_posted_thread(r, thread, status) +#define ngx_http_lua_probe_coroutine_done(r, co, success) #endif diff --git a/src/ngx_http_lua_uri.c b/src/ngx_http_lua_uri.c index 531782e77a..6fb913d8d0 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -40,8 +40,29 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) lua_pop(L, 1); if (n == 2) { + luaL_checktype(L, 2, LUA_TBOOLEAN); jump = lua_toboolean(L, 2); + + if (jump) { + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + dd("rewrite: %d, access: %d, content: %d", + (int) ctx->entered_rewrite_phase, + (int) ctx->entered_access_phase, + (int) ctx->entered_content_phase); + + 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_http_lua_check_if_abortable(L, ctx); + } } p = (u_char *) luaL_checklstring(L, 1, &len); @@ -65,24 +86,6 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) ngx_http_set_exten(r); if (jump) { - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return luaL_error(L, "no ctx found"); - } - - dd("rewrite: %d, access: %d, content: %d", - (int) ctx->entered_rewrite_phase, - (int) ctx->entered_access_phase, - (int) ctx->entered_content_phase); - - 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_http_lua_check_if_abortable(L, ctx); - r->uri_changed = 1; return lua_yield(L, 0); diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 9f0d9ab282..0d7622003c 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -11,6 +11,7 @@ static int ngx_http_lua_uthread_spawn(lua_State *L); +static int ngx_http_lua_uthread_wait(lua_State *L); void @@ -22,6 +23,9 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_uthread_spawn); lua_setfield(L, -2, "spawn"); + lua_pushcfunction(L, ngx_http_lua_uthread_wait); + lua_setfield(L, -2, "wait"); + lua_setfield(L, -2, "thread"); } @@ -49,13 +53,96 @@ ngx_http_lua_uthread_spawn(lua_State *L) coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ctx->co_op = NGX_HTTP_LUA_USER_THREAD_RESUME; + ctx->cur_co_ctx->thread_spawn_yielded = 1; + if (ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx) != NGX_OK) { return luaL_error(L, "out of memory"); } + coctx->parent_co_ctx = ctx->cur_co_ctx; ctx->cur_co_ctx = coctx; - ngx_http_lua_probe_user_thread_create(r, L, coctx->co); + ngx_http_lua_probe_user_thread_spawn(r, L, coctx->co); + + return lua_yield(L, 1); +} + + +static int +ngx_http_lua_uthread_wait(lua_State *L) +{ + int n; + lua_State *sub_co; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx, *sub_coctx; + + sub_co = lua_tothread(L, 1); + + luaL_argcheck(L, sub_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); + + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + 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); + + coctx = ctx->cur_co_ctx; + + sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx); + if (sub_coctx == NULL) { + return luaL_error(L, "no co ctx found for the ngx.thread " + "instance given"); + } + + if (sub_coctx->parent_co_ctx != coctx) { + return luaL_error(L, "only parent coroutine can wait on the " + "ngx.thread instance"); + } + + switch (sub_coctx->co_status) { + case NGX_HTTP_LUA_CO_DEAD: + return luaL_error(L, "the ngx.thread instance already dead"); + + case NGX_HTTP_LUA_CO_ZOMBIE: + + ngx_http_lua_probe_info("found zombie child"); + + n = 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)); + + if (n) { + lua_xmove(sub_coctx->co, L, n); + } + +#if 1 + ngx_http_lua_del_thread(r, L, ctx, sub_coctx); + ctx->uthreads--; +#endif + + return n; + + default: + /* still alive */ + break; + } + + sub_coctx->waited_by_parent = 1; return lua_yield(L, 0); } diff --git a/src/ngx_http_lua_uthread.h b/src/ngx_http_lua_uthread.h index 4180fec0a0..a7ab67a1e5 100644 --- a/src/ngx_http_lua_uthread.h +++ b/src/ngx_http_lua_uthread.h @@ -10,13 +10,18 @@ #define ngx_http_lua_is_entry_thread(ctx) \ - ((ctx)->cur_co_ctx == &ctx->entry_co_ctx) + ((ctx)->cur_co_ctx == &(ctx)->entry_co_ctx) #define ngx_http_lua_entry_thread_alive(ctx) \ ((ctx)->entry_co_ctx.co_ref != LUA_NOREF) +#define ngx_http_lua_coroutine_alive(coctx) \ + ((coctx)->co_status != NGX_HTTP_LUA_CO_DEAD \ + && (coctx)->co_status != NGX_HTTP_LUA_CO_ZOMBIE) + + void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 833ee598c1..a15c859d83 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -41,6 +41,14 @@ #include "ngx_http_lua_uthread.h" +#if 0 +#ifdef ngx_http_lua_probe_info +#undef ngx_http_lua_probe_info +#endif +#define ngx_http_lua_probe_info(msg) +#endif + + char ngx_http_lua_code_cache_key; char ngx_http_lua_ctx_tables_key; char ngx_http_lua_regex_cache_key; @@ -67,8 +75,6 @@ static void ngx_http_lua_inject_ngx_api(ngx_conf_t *cf, lua_State *L); static void ngx_http_lua_inject_arg_api(lua_State *L); static int ngx_http_lua_param_get(lua_State *L); static int ngx_http_lua_param_set(lua_State *L); -static void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, - ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); static void ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx); static ngx_int_t ngx_http_lua_output_filter(ngx_http_request_t *r, @@ -77,6 +83,10 @@ static ngx_int_t ngx_http_lua_send_special(ngx_http_request_t *r, ngx_uint_t flags); static void ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); +static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, + ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread); +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); #ifndef LUA_PATH_SEP @@ -282,7 +292,7 @@ ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *L, int *ref) } -static void +void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx) { @@ -291,7 +301,7 @@ ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua deleting lightweight thread"); + "lua deleting light thread"); lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -316,7 +326,7 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, ngx_http_lua_co_ctx_t *entry_coctx; ngx_http_lua_co_ctx_t *cc; - if (ctx->uthreads) { + if (ctx->uthreads && ctx->user_co_ctx) { /* release all pending user threads */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); @@ -922,8 +932,8 @@ 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; - int rv, nrets; + ngx_http_lua_co_ctx_t *next_coctx, *parent_coctx; + int rv, nrets, success = 1; lua_State *next_co; lua_State *old_co; const char *err, *msg, *trace; @@ -936,6 +946,16 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread, top:%d", lua_gettop(L)); + if (ctx->cur_co_ctx->thread_spawn_yielded) { + ngx_http_lua_probe_info("thread spawn yielded"); + + ctx->cur_co_ctx->thread_spawn_yielded = 0; + nrets = 1; + + } else { + nrets = nret; + } + /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); @@ -943,8 +963,6 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, NGX_LUA_EXCEPTION_TRY { - nrets = nret; - for ( ;; ) { dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, @@ -1017,6 +1035,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua user thread resume"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; + nrets = 0; break; @@ -1052,6 +1071,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_settop(ctx->cur_co_ctx->co, 0); + ngx_http_lua_probe_info("set co running"); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; if (ctx->posted_threads) { @@ -1096,30 +1116,68 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, case 0: + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; - if (ngx_http_lua_is_thread(ctx)) { - /* a lightweight thread is terminated successfully */ + if (ctx->cur_co_ctx->zombie_child_threads) { + ngx_http_lua_cleanup_zombie_child_uthreads(r, L, ctx, + ctx->cur_co_ctx); + } - lua_settop(L, 0); /* discard return values */ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua light thread ended normally"); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua lightweight thread ended normally"); + if (ngx_http_lua_is_entry_thread(ctx)) { - if (ngx_http_lua_is_entry_thread(ctx)) { - ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); + lua_settop(L, 0); - if (ctx->uthreads) { - ctx->cur_co_ctx = NULL; - return NGX_AGAIN; - } + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); - /* all user threads terminated already */ - goto done; + dd("uthreads: %d", (int) ctx->uthreads); + + if (ctx->uthreads) { + + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; } + /* all user threads terminated already */ + goto done; + } + + if (ctx->cur_co_ctx->is_uthread) { /* being a user thread */ + lua_settop(L, 0); + + if (ctx->cur_co_ctx->waited_by_parent) { + ngx_http_lua_probe_info("parent already waiting"); + ctx->cur_co_ctx->waited_by_parent = 0; + success = 1; + goto user_co_done; + } + + parent_coctx = ctx->cur_co_ctx->parent_co_ctx; + + if (ngx_http_lua_coroutine_alive(parent_coctx)) { + ngx_http_lua_probe_info("parent still alive"); + + if (ngx_http_lua_post_zombie_thread(r, parent_coctx, + ctx->cur_co_ctx) + != NGX_OK) + { + return NGX_ERROR; + } + + lua_pushboolean(ctx->cur_co_ctx->co, 1); + lua_insert(ctx->cur_co_ctx->co, 1); + + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_ZOMBIE; + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); ctx->uthreads--; @@ -1140,12 +1198,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* being a user coroutine that has a parent */ + success = 1; + +user_co_done: nrets = lua_gettop(ctx->cur_co_ctx->co); next_coctx = ctx->cur_co_ctx->parent_co_ctx; if (next_coctx == NULL) { - /* being a lightweight thread */ + /* being a light thread */ goto no_parent; } @@ -1155,16 +1216,22 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, * ended successful, coroutine.resume returns true plus * any return values */ - lua_pushboolean(next_co, 1); + lua_pushboolean(next_co, success); if (nrets) { lua_xmove(ctx->cur_co_ctx->co, next_co, nrets); } + if (ctx->cur_co_ctx->is_uthread) { + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); + ctx->uthreads--; + } + nrets++; ctx->cur_co_ctx = next_coctx; - dd("set coroutine to running"); + ngx_http_lua_probe_info("set parent running"); + next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1201,20 +1268,73 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, msg = "unknown reason"; } + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 0); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; ngx_http_lua_thread_traceback(L, ctx->cur_co_ctx->co, ctx->cur_co_ctx); trace = lua_tostring(L, -1); - lua_pop(L, 1); - if (ngx_http_lua_is_thread(ctx)) { + if (ctx->cur_co_ctx->is_uthread) { + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "lua user thread aborted: %s: %s\n%s", + err, msg, trace); + + lua_settop(L, 0); + + if (ctx->cur_co_ctx->waited_by_parent) { + ctx->cur_co_ctx->waited_by_parent = 0; + success = 0; + goto user_co_done; + } + + parent_coctx = ctx->cur_co_ctx->parent_co_ctx; + + if (ngx_http_lua_coroutine_alive(parent_coctx)) { + if (ngx_http_lua_post_zombie_thread(r, parent_coctx, + ctx->cur_co_ctx) + != NGX_OK) + { + return NGX_ERROR; + } + + lua_pushboolean(ctx->cur_co_ctx->co, 0); + lua_insert(ctx->cur_co_ctx->co, 1); + + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_ZOMBIE; + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } + + ngx_http_lua_del_thread(r, L, ctx, ctx->cur_co_ctx); + ctx->uthreads--; + + if (ctx->uthreads == 0) { + if (ngx_http_lua_entry_thread_alive(ctx)) { + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } + + /* all threads terminated already */ + goto done; + } + + /* some other user threads still running */ + ctx->cur_co_ctx = NULL; + return NGX_AGAIN; + } + + if (ngx_http_lua_is_entry_thread(ctx)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "lua thread aborted: %s: %s\n%s", + "lua entry thread aborted: %s: %s\n%s", err, msg, trace); lua_settop(L, 0); + /* being the entry thread aborted */ + ngx_http_lua_request_cleanup(r); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1236,6 +1356,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, next_co = next_coctx->co; + ngx_http_lua_probe_info("set parent running"); + next_coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; /* @@ -1861,6 +1983,8 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, "lua thread initiated internal redirect to %V", &ctx->exec_uri); + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; ngx_http_lua_request_cleanup(r); @@ -1944,6 +2068,8 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, } #endif + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; ngx_http_lua_request_cleanup(r); @@ -2199,6 +2325,8 @@ 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); + ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); + ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; ngx_http_lua_request_cleanup(r); @@ -2751,3 +2879,43 @@ ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } } + +static ngx_int_t +ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, + ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread) +{ + ngx_http_lua_posted_thread_t **p; + ngx_http_lua_posted_thread_t *pt; + + pt = ngx_palloc(r->pool, sizeof(ngx_http_lua_posted_thread_t)); + if (pt == NULL) { + return NGX_ERROR; + } + + pt->co_ctx = thread; + pt->next = NULL; + + for (p = &parent->zombie_child_threads; *p; p = &(*p)->next) { /* void */ } + + *p = pt; + + return NGX_OK; +} + + +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) +{ + ngx_http_lua_posted_thread_t *pt; + + for (pt = coctx->zombie_child_threads; pt; pt = pt->next) { + if (pt->co_ctx->co_ref != LUA_NOREF) { + ngx_http_lua_del_thread(r, L, ctx, pt->co_ctx); + ctx->uthreads--; + } + } + + coctx->zombie_child_threads = NULL; +} + diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 10ba703f58..b410f7422e 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -131,6 +131,9 @@ ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); +void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index ce7d2396af..ec10f8c75b 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -44,7 +44,8 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 @@ -78,8 +79,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -154,10 +157,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -240,13 +244,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -325,19 +331,21 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index d773fdd70e..8cff1d1ebd 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -7,7 +7,7 @@ use t::StapThread; our $GCScript = $t::StapThread::GCScript; our $StapScript = $t::StapThread::StapScript; -#repeat_each(2); +repeat_each(2); plan tests => repeat_each() * (blocks() * 4); @@ -72,9 +72,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 --- response_body @@ -150,14 +152,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -238,17 +242,20 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 delete thread 3 +terminate 4: ok delete thread 4 free request @@ -282,9 +289,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -372,15 +382,17 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua tcp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -469,15 +481,17 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua udp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -561,14 +575,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -662,14 +678,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -769,14 +787,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -864,14 +884,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua udp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -953,14 +975,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -1038,14 +1062,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua req body cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -1123,21 +1149,26 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +before +hello in thread +after +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -1207,21 +1238,24 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -1297,20 +1331,23 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] diff --git a/t/023-rewrite/uthread-redirect.t b/t/023-rewrite/uthread-redirect.t index 53f56c3744..9901719369 100644 --- a/t/023-rewrite/uthread-redirect.t +++ b/t/023-rewrite/uthread-redirect.t @@ -93,22 +93,25 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -174,10 +177,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index 10016ff202..9af29d6f80 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -7,7 +7,7 @@ use t::StapThread; our $GCScript = $t::StapThread::GCScript; our $StapScript = $t::StapThread::StapScript; -#repeat_each(2); +repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 1); @@ -51,9 +51,12 @@ _EOC_ --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -93,12 +96,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1 +terminate 4: ok delete thread 4 --- response_body @@ -135,9 +142,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -182,12 +192,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 3: ok delete thread 3 +terminate 2: ok delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -223,14 +237,18 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +terminate 1: ok delete thread 2 delete thread 1 +terminate 3: ok +delete thread 3 ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body +after --- error_log -lua thread aborted: runtime error: [string "rewrite_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: [string "rewrite_by_lua"]:3: attempt to call field 'blah' (a nil value) @@ -265,9 +283,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -317,9 +338,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -371,9 +395,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -441,12 +468,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -490,12 +521,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 -delete thread 3 +spawn user thread 3 in 2 +terminate 3: ok +terminate 1: ok delete thread 1 +terminate 2: ok +delete thread 3 delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -536,12 +571,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -576,9 +615,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -608,13 +650,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body -status: dead +status: zombie --- no_error_log [error] @@ -646,10 +691,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 +terminate 1: ok delete thread 1 +terminate 3: ok +terminate 2: ok delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -687,9 +736,13 @@ GET /lua --- stap_out create 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 3: ok +terminate 2: ok delete thread 3 +terminate 1: ok delete thread 1 +terminate 4: ok delete thread 4 --- response_body @@ -737,9 +790,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -792,12 +848,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -836,9 +896,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -875,18 +938,25 @@ GET /lua --- stap eval: $::GCScript --- stap_out_like ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3|create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1) +terminate 4: ok delete thread 4$ --- response_body @@ -935,9 +1005,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -983,9 +1056,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- udp_listen: 12345 @@ -1023,12 +1099,17 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2) +terminate 3: ok delete thread 3$ --- response_body_like chop @@ -1071,12 +1152,17 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2) +terminate 3: ok delete thread 3$ --- response_body_like chop diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 669839bf7f..48eace209d 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -44,7 +44,8 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 @@ -78,8 +79,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -154,10 +157,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -240,13 +244,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -325,19 +331,21 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 260318f1e8..099d23adad 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -7,7 +7,7 @@ use t::StapThread; our $GCScript = $t::StapThread::GCScript; our $StapScript = $t::StapThread::StapScript; -#repeat_each(2); +repeat_each(2); plan tests => repeat_each() * (blocks() * 4); @@ -72,9 +72,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 --- response_body @@ -150,14 +152,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -238,17 +242,20 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 delete thread 3 +terminate 4: ok delete thread 4 free request @@ -282,9 +289,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -372,15 +382,17 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua tcp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -469,15 +481,17 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua udp resolve cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -561,14 +575,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -662,14 +678,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -769,14 +787,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -864,14 +884,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua udp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -953,14 +975,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -1038,14 +1062,16 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua req body cleanup delete timer 12000 delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 free request @@ -1123,21 +1149,26 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +before +hello in thread +after +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -1207,21 +1238,24 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -1297,20 +1331,23 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] diff --git a/t/024-access/uthread-redirect.t b/t/024-access/uthread-redirect.t index 199d158c87..4bfb84ab1f 100644 --- a/t/024-access/uthread-redirect.t +++ b/t/024-access/uthread-redirect.t @@ -93,22 +93,25 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -174,10 +177,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index 633a4062d6..ed90869798 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -7,7 +7,7 @@ use t::StapThread; our $GCScript = $t::StapThread::GCScript; our $StapScript = $t::StapThread::StapScript; -#repeat_each(2); +repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 1); @@ -51,9 +51,12 @@ _EOC_ --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -93,12 +96,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1 +terminate 4: ok delete thread 4 --- response_body @@ -135,9 +142,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -182,12 +192,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 3: ok delete thread 3 +terminate 2: ok delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -223,14 +237,18 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +terminate 1: ok delete thread 2 delete thread 1 +terminate 3: ok +delete thread 3 ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body +after --- error_log -lua thread aborted: runtime error: [string "access_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: [string "access_by_lua"]:3: attempt to call field 'blah' (a nil value) @@ -265,9 +283,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -317,9 +338,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -371,9 +395,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -441,12 +468,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -490,12 +521,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 -delete thread 3 +spawn user thread 3 in 2 +terminate 3: ok +terminate 1: ok delete thread 1 +terminate 2: ok +delete thread 3 delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -536,12 +571,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -576,9 +615,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -608,13 +650,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body -status: dead +status: zombie --- no_error_log [error] @@ -646,10 +691,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 +terminate 1: ok delete thread 1 +terminate 3: ok +terminate 2: ok delete thread 2 +terminate 4: ok delete thread 4 --- response_body @@ -687,9 +736,13 @@ GET /lua --- stap_out create 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 3: ok +terminate 2: ok delete thread 3 +terminate 1: ok delete thread 1 +terminate 4: ok delete thread 4 --- response_body @@ -737,9 +790,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 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 --- response_body @@ -792,12 +848,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 +terminate 4: ok delete thread 4 --- response_body @@ -836,9 +896,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -875,18 +938,25 @@ GET /lua --- stap eval: $::GCScript --- stap_out_like ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3|create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1) +terminate 4: ok delete thread 4$ --- response_body @@ -935,9 +1005,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -983,9 +1056,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- udp_listen: 12345 @@ -1023,12 +1099,17 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2) +terminate 3: ok delete thread 3$ --- response_body_like chop @@ -1071,12 +1152,17 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2) +terminate 3: ok delete thread 3$ --- response_body_like chop diff --git a/t/034-match.t b/t/034-match.t index 2dbc0c123f..5f17f0513c 100644 --- a/t/034-match.t +++ b/t/034-match.t @@ -641,7 +641,7 @@ regex: (?:>[\w\s]*) --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log chop -lua 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]+") +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]+") diff --git a/t/044-req-body.t b/t/044-req-body.t index 26e8b75229..1e167d70ef 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -564,7 +564,7 @@ qr/500 Internal Server Error/] --- error_code eval [200, 500] --- error_log eval -[qr{\[error\].*? lua thread aborted: runtime error: \[string "rewrite_by_lua"\]:3: stat\(\) "[^"]+/a\.txt" failed} +[qr{\[error\].*? lua entry thread aborted: runtime error: \[string "rewrite_by_lua"\]:3: stat\(\) "[^"]+/a\.txt" failed} ] diff --git a/t/057-flush-timeout.t b/t/057-flush-timeout.t index 054f820528..4b7b95323f 100644 --- a/t/057-flush-timeout.t +++ b/t/057-flush-timeout.t @@ -194,10 +194,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: ok lua flush cleanup delete timer 200 delete thread 2 diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 69b032b26b..accc1614a5 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -654,10 +654,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 diff --git a/t/073-backtrace.t b/t/073-backtrace.t index cd2cfb1233..26656576cc 100644 --- a/t/073-backtrace.t +++ b/t/073-backtrace.t @@ -59,7 +59,7 @@ attempt to call global 'lua_concat' GET /lua --- ignore_response --- error_log -lua thread aborted: runtime error: unknown reason +lua entry thread aborted: runtime error: unknown reason stack traceback: in function 'error' : in function 'bar' diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 403c79ca77..5e11b144f1 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -39,7 +39,9 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 @@ -79,10 +81,13 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1 @@ -119,8 +124,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -164,11 +171,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 3: ok delete thread 3 +terminate 2: ok delete thread 2 --- response_body @@ -203,14 +213,16 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +terminate 1: ok delete thread 2 delete thread 1 ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body +after --- error_log -lua thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) +lua user thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) @@ -244,8 +256,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -294,8 +308,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -346,7 +362,9 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 @@ -414,11 +432,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 +terminate 3: ok delete thread 3 --- response_body @@ -461,11 +482,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 -delete thread 3 +spawn user thread 3 in 2 +terminate 3: ok +terminate 1: ok delete thread 1 +terminate 2: ok +delete thread 3 delete thread 2 --- response_body @@ -505,11 +529,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -543,8 +570,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -573,12 +602,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 --- response_body -status: dead +status: zombie --- no_error_log [error] @@ -609,9 +640,12 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 2 +terminate 1: ok delete thread 1 +terminate 3: ok +terminate 2: ok delete thread 2 --- response_body @@ -648,8 +682,11 @@ GET /lua --- stap_out create 2 in 1 create 3 in 2 -create user thread 3 in 2 +spawn user thread 3 in 2 +terminate 3: ok +terminate 2: ok delete thread 3 +terminate 1: ok delete thread 1 --- response_body @@ -696,7 +733,9 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1 @@ -749,11 +788,14 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3 --- response_body @@ -791,8 +833,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -828,16 +872,22 @@ GET /lua --- stap eval: $::GCScript --- stap_out_like ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 +terminate 3: ok delete thread 3|create 2 in 1 -create user thread 2 in 1 -delete thread 2 +spawn user thread 2 in 1 +terminate 2: ok create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +terminate 1: ok +delete thread 2 delete thread 3 delete thread 1)$ @@ -886,8 +936,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -932,8 +984,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- udp_listen: 12345 @@ -970,11 +1024,15 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2)$ --- response_body_like chop @@ -1016,11 +1074,15 @@ hello world --- stap eval: $::GCScript --- stap_out_like chop ^(?:create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok delete thread 2 delete thread 1|create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2)$ --- response_body_like chop diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 507e891582..882e32acee 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -71,7 +71,8 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 @@ -147,10 +148,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -233,13 +235,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -275,8 +279,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -363,11 +369,12 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua tcp resolve cleanup delete timer 12000 delete thread 2 @@ -458,11 +465,12 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 resolving www.google.com add timer 12000 expire timer 100 +terminate 2: ok lua udp resolve cleanup delete timer 12000 delete thread 2 @@ -548,10 +556,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 @@ -647,10 +656,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 @@ -752,10 +762,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 @@ -845,10 +856,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua udp socket cleanup delete timer 12000 delete thread 2 @@ -932,10 +944,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua tcp socket cleanup delete timer 12000 delete thread 2 @@ -1015,10 +1028,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 12000 expire timer 100 +terminate 2: ok lua req body cleanup delete timer 12000 delete thread 2 @@ -1098,13 +1112,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 free request --- ignore_response @@ -1181,21 +1197,22 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -1270,11 +1287,103 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok +delete thread 2 +delete thread 1 +free request + +--- response_body +end +--- error_log +attempt to abort with pending subrequests + + + +=== TEST 16: exit in entry thread (user thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + end + + ngx.thread.spawn(f) + + ngx.sleep(0.1) + ngx.exit(0) + '; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 1: fail delete thread 2 delete thread 1 delete timer 200 diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 8016a13dce..0089d44fd1 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -43,7 +43,8 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 @@ -76,8 +77,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -151,10 +154,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -236,13 +240,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -320,10 +326,93 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +terminate 1: ok +delete thread 2 +delete thread 1 +free request + +--- response_body +end +--- error_log +attempt to abort with pending subrequests + + + +=== TEST 6: exec in entry thread (user thread is still pending on ngx.location.capture), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.location.capture("/sleep") + ngx.say("end") + end + + ngx.thread.spawn(f) + + ngx.sleep(0.1) + ngx.exec("/foo") + '; + } + + location = /sleep { + echo_sleep 0.2; + } + + location = /foo { + echo hello world; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +terminate 1: fail delete thread 2 delete thread 1 delete timer 200 diff --git a/t/096-uthread-redirect.t b/t/096-uthread-redirect.t index 794578055e..8a756ed45d 100644 --- a/t/096-uthread-redirect.t +++ b/t/096-uthread-redirect.t @@ -92,22 +92,23 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 post subreq /echo add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] @@ -172,10 +173,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -187,3 +189,94 @@ free request --- no_error_log [error] + + +=== TEST 3: ngx.redirect() in entry thread (user thread is still pending on ngx.location.capture_multi), without pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.location.capture_multi{ + {"/echo"}, + {"/sleep"} + } + ngx.say("end") + end + + ngx.thread.spawn(f) + + ngx.sleep(0.1) + ngx.redirect(301) + '; + } + + location = /echo { + echo hello; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +add timer 100 +post subreq /echo +add timer 200 +expire timer 100 +terminate 1: fail +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- error_log +attempt to abort with pending subrequests +--- no_error_log +[alert] +[warn] + diff --git a/t/097-uthread-rewrite.t b/t/097-uthread-rewrite.t index bbfc748d8d..bb3b724a66 100644 --- a/t/097-uthread-rewrite.t +++ b/t/097-uthread-rewrite.t @@ -43,7 +43,8 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok delete thread 2 delete thread 1 @@ -76,8 +77,10 @@ GET /lua --- stap eval: $::GCScript --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok delete thread 1 +terminate 2: ok delete thread 2 --- response_body @@ -151,10 +154,11 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 1000 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -236,13 +240,15 @@ _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 create 3 in 1 -create user thread 3 in 1 +spawn user thread 3 in 1 add timer 1000 +terminate 1: ok delete thread 1 expire timer 100 +terminate 2: ok lua sleep cleanup delete timer 1000 delete thread 2 @@ -271,6 +277,7 @@ hello foo ngx.location.capture("/sleep") ngx.say("end") '; + content_by_lua return; } location = /sleep { @@ -316,23 +323,31 @@ M(timer-expire) { delete timers[$arg1] } } + +F(ngx_http_lua_post_subrequest) { + printf("post subreq %s\n", ngx_http_req_uri($r)) +} + _EOC_ --- stap_out create 2 in 1 -create user thread 2 in 1 +spawn user thread 2 in 1 add timer 100 add timer 200 expire timer 100 +terminate 2: fail +expire timer 200 +post subreq /sleep +terminate 1: ok delete thread 2 delete thread 1 -delete timer 200 +terminate 3: ok +delete thread 3 free request ---- ignore_response +--- response_body +end --- error_log attempt to abort with pending subrequests ---- no_error_log -[alert] -[warn] diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t new file mode 100644 index 0000000000..af0a588b0d --- /dev/null +++ b/t/098-uthread-wait.t @@ -0,0 +1,586 @@ +# 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; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: simple user thread wait without I/O +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to run thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +hello in thread +thread created: zombie +done +--- no_error_log +[error] + + + +=== TEST 2: simple user thread wait with I/O +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("hello in thread") + return "done" + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to wait thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +thread created: running +hello in thread +done +--- no_error_log +[error] + + + +=== TEST 3: wait on uthreads on the reversed order of their termination +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f: hello") + return "done" + end + + function g() + ngx.sleep(0.2) + ngx.say("g: hello") + return "done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tg) + if not ok then + ngx.say("failed to wait g: ", res) + return + end + + ngx.say("g: ", res) + + ngx.say("f thread status: ", coroutine.status(tf)) + + ok, res = ngx.thread.wait(tf) + if not ok then + ngx.say("failed to wait f: ", res) + return + end + + ngx.say("f: ", res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +terminate 3: ok +delete thread 3 +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +f thread created: running +g thread created: running +f: hello +g: hello +g: done +f thread status: zombie +f: done +--- no_error_log +[error] + + + +=== TEST 4: wait on uthreads on the exact order of their termination +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f: hello") + return "done" + end + + function g() + ngx.sleep(0.2) + ngx.say("g: hello") + return "done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf) + if not ok then + ngx.say("failed to wait f: ", res) + return + end + + ngx.say("f: ", res) + + ngx.say("g thread status: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tg) + if not ok then + ngx.say("failed to wait g: ", res) + return + end + + ngx.say("g: ", res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 1: ok +delete thread 1 + +--- response_body +f thread created: running +g thread created: running +f: hello +f: done +g thread status: running +g: hello +g: done +--- no_error_log +[error] + + + +=== TEST 5: simple user thread wait without I/O (return multiple values) +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + return "done", 3.14 + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res1, res2 = ngx.thread.wait(t) + if not ok then + ngx.say("failed to run thread: ", res1) + return + end + + ngx.say("res: ", res1, " ", res2) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +hello in thread +thread created: zombie +res: done 3.14 +--- no_error_log +[error] + + + +=== TEST 6: simple user thread wait with I/O, return multiple values +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("hello in thread") + return "done", 3.14 + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + local ok, res1, res2 = ngx.thread.wait(t) + if not ok then + ngx.say("failed to wait thread: ", res1) + return + end + + ngx.say("res: ", res1, " ", res2) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +thread created: running +hello in thread +res: done 3.14 +--- no_error_log +[error] + + + +=== TEST 7: simple user thread wait without I/O, throw errors +--- config + location /lua { + content_by_lua ' + function f() + ngx.say("hello in thread") + error("bad bad!") + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to wait thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +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! + + + +=== TEST 8: simple user thread wait with I/O, throw errors +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("hello in thread") + error("bad bad!") + end + + local t, err = ngx.thread.spawn(f) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to wait thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +delete thread 2 +terminate 1: ok +delete thread 1 + +--- response_body +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! + + + +=== TEST 9: simple user thread wait without I/O (in a user coroutine) +--- config + location /lua { + content_by_lua ' + function g() + ngx.say("hello in thread") + return "done" + end + + function f() + local t, err = ngx.thread.spawn(g) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to run thread: ", res) + return + end + + ngx.say(res) + end + + local co = coroutine.create(f) + coroutine.resume(co) + '; + } +--- request +GET /lua +--- 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 +terminate 1: ok +delete thread 1 + +--- response_body +hello in thread +thread created: zombie +done +--- no_error_log +[error] + + + +=== TEST 10: simple user thread wait with I/O (in a user coroutine) +--- config + location /lua { + content_by_lua ' + function g() + ngx.sleep(0.1) + ngx.say("hello in thread") + return "done" + end + + function f() + local t, err = ngx.thread.spawn(g) + if not t then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("thread created: ", coroutine.status(t)) + + collectgarbage() + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to run thread: ", res) + return + end + + ngx.say(res) + end + + local co = coroutine.create(f) + coroutine.resume(co) + '; + } +--- request +GET /lua +--- 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 +terminate 1: ok +delete thread 1 + +--- response_body +thread created: running +hello in thread +done +--- no_error_log +[error] + diff --git a/t/StapThread.pm b/t/StapThread.pm index 8b91f0d3f9..d06f3eae49 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -25,10 +25,10 @@ F(ngx_http_free_request) { in_req-- } -M(http-lua-user-thread-create) { +M(http-lua-user-thread-spawn) { p = gen_id($arg2) c = gen_id($arg3) - printf("create user thread %x in %x\n", c, p) + printf("spawn user thread %x in %x\n", c, p) } M(http-lua-thread-delete) { @@ -42,6 +42,12 @@ M(http-lua-user-coroutine-create) { printf("create %x in %x\n", c, p) } +M(http-lua-coroutine-done) { + t = gen_id($arg2) + printf("terminate %d: %s\n", t, $arg3 ? "ok" : "fail") + #print_ubacktrace() +} + _EOC_ our $StapScript = <<'_EOC_'; @@ -104,17 +110,15 @@ F(ngx_http_lua_run_thread) { #} } -/* probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { id = gen_id($L) printf("lua resume %d\n", id) } -*/ -M(http-lua-user-thread-create) { +M(http-lua-user-thread-spawn) { p = gen_id($arg2) c = gen_id($arg3) - printf("create uthread %x in %x\n", c, p) + printf("spawn uthread %x in %x\n", c, p) } M(http-lua-thread-delete) { @@ -195,6 +199,16 @@ F(ngx_http_lua_ngx_exit) { F(ngx_http_lua_sleep_resume) { println("lua sleep resume") } + +M(http-lua-coroutine-done) { + t = gen_id($arg2) + printf("terminate coro %d: %s\n", t, $arg3 ? "ok" : "fail") +} + +M(http-lua-info) { + msg = user_string($arg1) + printf("lua info: %s\n", msg) +} _EOC_ 1; From b842f16a1b98e57dcd8a18b69f7a4d2225347bde Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 29 Sep 2012 23:55:18 -0700 Subject: [PATCH 0111/2239] refactor: removed the ctx->fatal field and just used ctx->no_abort instead. --- src/ngx_http_lua_common.h | 2 -- src/ngx_http_lua_util.c | 3 ++- src/ngx_http_lua_util.h | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 0c28c05e3c..426bffb87d 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -355,8 +355,6 @@ typedef struct ngx_http_lua_ctx_s { unsigned no_abort:1; /* prohibit "world abortion" via ngx.exit() and etc */ - - unsigned fatal:1; /* error is fatal */ } ngx_http_lua_ctx_t; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a15c859d83..c75da9c622 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1339,7 +1339,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, dd("headers sent? %d", ctx->headers_sent ? 1 : 0); - if (ctx->fatal) { + if (ctx->no_abort) { + ctx->no_abort = 0; return NGX_ERROR; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index b410f7422e..80b63c5ac6 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -137,7 +137,6 @@ void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ - ctx->fatal = 1; \ return luaL_error(L, "attempt to abort with pending subrequests"); \ } From 4d0e77f5db73ebab2b608afe68abd9b36a1bdab1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 01:14:30 -0700 Subject: [PATCH 0112/2239] feature: ngx.thread.wait() can now take multiple user threads as its arguments and wait on all of them at the same time. it will return the first terminated user thread's result as soon as possible (that is, without waiting for other pending user threads to finish). --- src/ngx_http_lua_uthread.c | 72 +++---- src/ngx_http_lua_util.c | 26 +-- t/098-uthread-wait.t | 379 +++++++++++++++++++++++++++++++++++++ t/StapThread.pm | 5 + 4 files changed, 435 insertions(+), 47 deletions(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 0d7622003c..47fb128ba2 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -71,16 +71,12 @@ ngx_http_lua_uthread_spawn(lua_State *L) static int ngx_http_lua_uthread_wait(lua_State *L) { - int n; + int i, nargs, nrets; lua_State *sub_co; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx, *sub_coctx; - sub_co = lua_tothread(L, 1); - - luaL_argcheck(L, sub_co, 1, "coroutine expected"); - lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); @@ -101,48 +97,56 @@ ngx_http_lua_uthread_wait(lua_State *L) coctx = ctx->cur_co_ctx; - sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx); - if (sub_coctx == NULL) { - return luaL_error(L, "no co ctx found for the ngx.thread " - "instance given"); - } + nargs = lua_gettop(L); - if (sub_coctx->parent_co_ctx != coctx) { - return luaL_error(L, "only parent coroutine can wait on the " - "ngx.thread instance"); - } + for (i = 1; i <= nargs; i++) { + sub_co = lua_tothread(L, i); - switch (sub_coctx->co_status) { - case NGX_HTTP_LUA_CO_DEAD: - return luaL_error(L, "the ngx.thread instance already dead"); + luaL_argcheck(L, sub_co, i, "lua thread expected"); - case NGX_HTTP_LUA_CO_ZOMBIE: + sub_coctx = ngx_http_lua_get_co_ctx(sub_co, ctx); + if (sub_coctx == NULL) { + return luaL_error(L, "no co ctx found for the ngx.thread " + "instance given"); + } - ngx_http_lua_probe_info("found zombie child"); + if (sub_coctx->parent_co_ctx != coctx) { + return luaL_error(L, "only parent coroutine can wait on the " + "ngx.thread instance"); + } - n = lua_gettop(sub_coctx->co); + switch (sub_coctx->co_status) { + case NGX_HTTP_LUA_CO_DEAD: + return luaL_error(L, "the ngx.thread instance already dead"); - dd("child retval count: %d, %s: %s", n, - luaL_typename(sub_coctx->co, -1), - lua_tostring(sub_coctx->co, -1)); + case NGX_HTTP_LUA_CO_ZOMBIE: - if (n) { - lua_xmove(sub_coctx->co, L, n); - } + ngx_http_lua_probe_info("found zombie child"); + + 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)); + + if (nrets) { + lua_xmove(sub_coctx->co, L, nrets); + } #if 1 - ngx_http_lua_del_thread(r, L, ctx, sub_coctx); - ctx->uthreads--; + ngx_http_lua_del_thread(r, L, ctx, sub_coctx); + ctx->uthreads--; #endif - return n; + return nrets; - default: - /* still alive */ - break; - } + default: + /* still alive */ + break; + } - sub_coctx->waited_by_parent = 1; + sub_coctx->waited_by_parent = 1; + } return lua_yield(L, 0); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index c75da9c622..81442878d6 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1151,16 +1151,16 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_settop(L, 0); - if (ctx->cur_co_ctx->waited_by_parent) { - ngx_http_lua_probe_info("parent already waiting"); - ctx->cur_co_ctx->waited_by_parent = 0; - success = 1; - goto user_co_done; - } - parent_coctx = ctx->cur_co_ctx->parent_co_ctx; if (ngx_http_lua_coroutine_alive(parent_coctx)) { + if (ctx->cur_co_ctx->waited_by_parent) { + ngx_http_lua_probe_info("parent already waiting"); + ctx->cur_co_ctx->waited_by_parent = 0; + success = 1; + goto user_co_done; + } + ngx_http_lua_probe_info("parent still alive"); if (ngx_http_lua_post_zombie_thread(r, parent_coctx, @@ -1284,15 +1284,15 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_settop(L, 0); - if (ctx->cur_co_ctx->waited_by_parent) { - ctx->cur_co_ctx->waited_by_parent = 0; - success = 0; - goto user_co_done; - } - parent_coctx = ctx->cur_co_ctx->parent_co_ctx; if (ngx_http_lua_coroutine_alive(parent_coctx)) { + if (ctx->cur_co_ctx->waited_by_parent) { + ctx->cur_co_ctx->waited_by_parent = 0; + success = 0; + goto user_co_done; + } + if (ngx_http_lua_post_zombie_thread(r, parent_coctx, ctx->cur_co_ctx) != NGX_OK) diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index af0a588b0d..68baf3d0e6 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -584,3 +584,382 @@ done --- no_error_log [error] + + +=== TEST 11: waiting on two simple user threads without I/O +--- config + location /lua { + content_by_lua ' + -- local out = function (...) ngx.log(ngx.ERR, ...) end + local out = ngx.say + + function f() + out("f: hello") + return "f done" + end + + function g() + out("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + out("failed to spawn thread f: ", err) + return + end + + out("thread f created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + out("failed to spawn thread g: ", err) + return + end + + out("thread g created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tf, tg) + if not ok then + out("failed to wait thread: ", res) + return + end + + out("res: ", res) + + out("f status: ", coroutine.status(tf)) + out("g status: ", coroutine.status(tg)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +create 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +delete thread 2 +terminate 1: ok +delete thread 3 +delete thread 1 + +--- response_body +f: hello +thread f created: zombie +g: hello +thread g created: zombie +res: f done +f status: dead +g status: zombie + +--- no_error_log +[error] + + + +=== TEST 12: waiting on two simple user threads with I/O +--- config + location /lua { + content_by_lua ' + -- local out = function (...) ngx.log(ngx.ERR, ...) end + local out = ngx.say + + function f() + ngx.sleep(0.1) + out("f: hello") + return "f done" + end + + function g() + ngx.sleep(0.2) + out("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + out("failed to spawn thread f: ", err) + return + end + + out("thread f created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + out("failed to spawn thread g: ", err) + return + end + + out("thread g created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tf, tg) + if not ok then + out("failed to wait thread: ", res) + return + end + + out("res: ", res) + + out("f status: ", coroutine.status(tf)) + out("g status: ", coroutine.status(tg)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 1 +terminate 3: ok +delete thread 3 + +--- response_body +thread f created: running +thread g created: running +f: hello +res: f done +f status: dead +g status: running +g: hello + +--- no_error_log +[error] + + + +=== TEST 13: waiting on two simple user threads with I/O (uthreads completed in reversed order) +--- config + location /lua { + content_by_lua ' + -- local out = function (...) ngx.log(ngx.ERR, ...) end + local out = ngx.say + + function f() + ngx.sleep(0.2) + out("f: hello") + return "f done" + end + + function g() + ngx.sleep(0.1) + out("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + out("failed to spawn thread f: ", err) + return + end + + out("thread f created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + out("failed to spawn thread g: ", err) + return + end + + out("thread g created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tf, tg) + if not ok then + out("failed to wait thread: ", res) + return + end + + out("res: ", res) + + out("f status: ", coroutine.status(tf)) + out("g status: ", coroutine.status(tg)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +delete thread 3 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +thread f created: running +thread g created: running +g: hello +res: g done +f status: running +g status: dead +f: hello + +--- no_error_log +[error] + + + +=== TEST 14: waiting on two simple user threads without I/O, both aborted by errors +--- config + location /lua { + content_by_lua ' + -- local out = function (...) ngx.log(ngx.ERR, ...) end + local out = ngx.say + + function f() + out("f: hello") + error("f done") + end + + function g() + out("g: hello") + error("g done") + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + out("failed to spawn thread f: ", err) + return + end + + out("thread f created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + out("failed to spawn thread g: ", err) + return + end + + out("thread g created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tf, tg) + if not ok then + out("failed to wait thread: ", res) + else + out("res: ", res) + end + + out("f status: ", coroutine.status(tf)) + out("g status: ", coroutine.status(tg)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: fail +create 3 in 1 +spawn user thread 3 in 1 +terminate 3: fail +delete thread 2 +terminate 1: ok +delete thread 3 +delete thread 1 + +--- response_body +f: hello +thread f created: zombie +g: hello +thread g created: zombie +failed to wait thread: f done +f status: dead +g status: zombie + +--- error_log +lua user thread aborted: runtime error: [string "content_by_lua"]:7: f done + + + +=== TEST 15: waiting on two simple user threads with I/O, both aborted by errors +--- config + location /lua { + content_by_lua ' + -- local out = function (...) ngx.log(ngx.ERR, ...) end + local out = ngx.say + + function f() + ngx.sleep(0.1) + out("f: hello") + error("f done") + end + + function g() + ngx.sleep(0.2) + out("g: hello") + error("g done") + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + out("failed to spawn thread f: ", err) + return + end + + out("thread f created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + out("failed to spawn thread g: ", err) + return + end + + out("thread g created: ", coroutine.status(tg)) + + local ok, res = ngx.thread.wait(tf, tg) + if not ok then + out("failed to wait thread: ", res) + else + out("res: ", res) + end + + out("f status: ", coroutine.status(tf)) + out("g status: ", coroutine.status(tg)) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 2: fail +delete thread 2 +terminate 1: ok +delete thread 1 +terminate 3: fail +delete thread 3 + +--- response_body +thread f created: running +thread g created: running +f: hello +failed to wait thread: f done +f status: dead +g status: running +g: hello + +--- error_log +lua user thread aborted: runtime error: [string "content_by_lua"]:8: f done + diff --git a/t/StapThread.pm b/t/StapThread.pm index d06f3eae49..9ae579e68b 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -209,6 +209,11 @@ M(http-lua-info) { msg = user_string($arg1) printf("lua info: %s\n", msg) } + +F(ngx_http_lua_uthread_wait) { + t = gen_id($L) + printf("lua thread %d waiting\n", t) +} _EOC_ 1; From d680b6b2ecade3fd4c3ed9a4d66c7be5a9e1e7ac Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 16:34:20 -0700 Subject: [PATCH 0113/2239] added (passing) tests for ngx.thread.wait(a, b) and the slower thread is aborted. --- t/098-uthread-wait.t | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 68baf3d0e6..a742978373 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -963,3 +963,142 @@ g: hello --- error_log lua user thread aborted: runtime error: [string "content_by_lua"]:8: f done + + +=== TEST 16: wait on uthreads on the exact order of their termination, but exit the world early +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f: hello") + return "done" + end + + function g() + ngx.sleep(0.2) + ngx.say("g: hello") + return "done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end + + ngx.say("res: ", res) + + ngx.exit(200) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 2: ok +delete thread 2 +terminate 1: ok +delete thread 3 +delete thread 1 + +--- response_body +f thread created: running +g thread created: running +f: hello +res: done + +--- no_error_log +[error] + + + +=== TEST 17: wait on uthreads on the reversed order of their termination, but exit the world early +--- ONLY +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "done" + end + + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end + + ngx.say("res: ", res) + + ngx.exit(200) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 3: ok +delete thread 3 +terminate 1: ok +delete thread 2 +delete thread 1 + +--- response_body +f thread created: running +g thread created: running +g: hello +res: done + +--- no_error_log +[error] + From 009911b4efa88425919d7d54d4f8959bc72a39c2 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 16:47:20 -0700 Subject: [PATCH 0114/2239] enabled all the test cases in 098-uthread-wait.t. --- t/098-uthread-wait.t | 1 - 1 file changed, 1 deletion(-) diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index a742978373..1003dac7a3 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1035,7 +1035,6 @@ res: done === TEST 17: wait on uthreads on the reversed order of their termination, but exit the world early ---- ONLY --- config location /lua { content_by_lua ' From 0ef27947a2477489c8a50bacb6fd214294874517 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 17:36:27 -0700 Subject: [PATCH 0115/2239] bugfix: ngx.thread.wait() did not croak when the argument coroutine is not a user thread at all. also added more tests for bad arguments to ngx.thread.wait(). --- src/ngx_http_lua_uthread.c | 12 +++--- t/098-uthread-wait.t | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 47fb128ba2..24de065837 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -110,15 +110,17 @@ ngx_http_lua_uthread_wait(lua_State *L) "instance given"); } + if (!sub_coctx->is_uthread) { + return luaL_error(L, "attempt to wait on a coroutine that is " + "not a user thread"); + } + if (sub_coctx->parent_co_ctx != coctx) { - return luaL_error(L, "only parent coroutine can wait on the " - "ngx.thread instance"); + return luaL_error(L, "only the parent coroutine can wait on the " + "thread"); } switch (sub_coctx->co_status) { - case NGX_HTTP_LUA_CO_DEAD: - return luaL_error(L, "the ngx.thread instance already dead"); - case NGX_HTTP_LUA_CO_ZOMBIE: ngx_http_lua_probe_info("found zombie child"); diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 1003dac7a3..81ed6d788f 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1101,3 +1101,88 @@ res: done --- no_error_log [error] + + +=== TEST 18: entry coroutine waiting on a thread not created by itself +--- config + location /lua { + content_by_lua ' + local t + + function f() + ngx.sleep(0.1) + return "done" + end + + function g() + t = ngx.thread.spawn(f) + end + + local co = coroutine.create(g) + coroutine.resume(co) + + local ok, res = ngx.thread.wait(t) + if not ok then + ngx.say("failed to run thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 2 +spawn user thread 3 in 2 +terminate 2: ok +terminate 1: fail +delete thread 3 +delete thread 1 + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- error_log +only the parent coroutine can wait on the thread + + + +=== TEST 19: entry coroutine waiting on a user coroutine +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + coroutine.yield() + return "done" + end + + local co = coroutine.create(f) + coroutine.resume(co) + + local ok, res = ngx.thread.wait(co) + if not ok then + ngx.say("failed to run thread: ", res) + return + end + + ngx.say(res) + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: fail +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 + From 56b9b8a46c71d3d2ba6fb12fb5d0e91de2da3783 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 18:52:58 -0700 Subject: [PATCH 0116/2239] polished the test for ngx.thread.wait a bit. --- t/098-uthread-wait.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 81ed6d788f..705262d101 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1041,13 +1041,13 @@ res: done function f() ngx.sleep(0.2) ngx.say("f: hello") - return "done" + return "f done" end function g() ngx.sleep(0.1) ngx.say("g: hello") - return "done" + return "g done" end local tf, err = ngx.thread.spawn(f) @@ -1096,7 +1096,7 @@ delete thread 1 f thread created: running g thread created: running g: hello -res: done +res: g done --- no_error_log [error] From fe4130e0f3604c878fee8acc41de7cceded9538d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 19:37:13 -0700 Subject: [PATCH 0117/2239] feature: ngx.thread.spawn(f, ...) can now take multiple arguments for the "light thread" coroutine's first resume. --- src/ngx_http_lua_uthread.c | 8 ++++++++ src/ngx_http_lua_util.c | 3 ++- t/093-uthread-spawn.t | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 24de065837..e0086e63b3 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -33,10 +33,13 @@ ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L) static int ngx_http_lua_uthread_spawn(lua_State *L) { + int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx = NULL; + n = lua_gettop(L); + ngx_http_lua_coroutine_create_helper(L, &r, &ctx, &coctx); /* anchor the newly created coroutine into the Lua registry */ @@ -47,6 +50,11 @@ ngx_http_lua_uthread_spawn(lua_State *L) coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); + if (n > 1) { + lua_replace(L, 1); + lua_xmove(L, coctx->co, n - 1); + } + coctx->is_uthread = 1; ctx->uthreads++; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 81442878d6..1a1b129373 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1035,7 +1035,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, "lua user thread resume"); ctx->co_op = NGX_HTTP_LUA_USER_CORO_NOP; - nrets = 0; + nrets = lua_gettop(ctx->cur_co_ctx->co) - 1; + dd("nrets = %d", nrets); break; diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 5e11b144f1..e2aa1fc525 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1095,3 +1095,37 @@ body: hello world)$ --- no_error_log [error] + + +=== TEST 24: simple user thread with args +--- config + location /lua { + content_by_lua ' + function f(a, b) + ngx.say("hello ", a, " and ", b) + end + + ngx.say("before") + ngx.thread.spawn(f, "foo", 3.14) + ngx.say("after") + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok +delete thread 2 +delete thread 1 + +--- response_body +before +hello foo and 3.14 +after +--- no_error_log +[error] + From 661c261bc3f14e0af9679d5f139e47fa6b171557 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 30 Sep 2012 22:13:23 -0700 Subject: [PATCH 0118/2239] refactor: disabled ngx_http_lua_probe_info by default. --- src/ngx_http_lua_socket_tcp.c | 6 ++++++ src/ngx_http_lua_socket_udp.c | 6 ++++++ src/ngx_http_lua_uthread.c | 6 ++++++ src/ngx_http_lua_util.c | 4 +--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 7f53b03efb..99b8c99be8 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -11,6 +11,12 @@ #include "ngx_http_lua_probe.h" +#if 1 +#undef ngx_http_lua_probe_info +#define ngx_http_lua_probe_info(msg) +#endif + + static int ngx_http_lua_socket_tcp(lua_State *L); static int ngx_http_lua_socket_tcp_connect(lua_State *L); static int ngx_http_lua_socket_tcp_receive(lua_State *L); diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 9eb2a6c289..c77f19a5d2 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -12,6 +12,12 @@ #include "ngx_http_lua_probe.h" +#if 1 +#undef ngx_http_lua_probe_info +#define ngx_http_lua_probe_info(msg) +#endif + + #define UDP_MAX_DATAGRAM_SIZE 8192 diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index e0086e63b3..425533248b 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -10,6 +10,12 @@ #include "ngx_http_lua_probe.h" +#if 1 +#undef ngx_http_lua_probe_info +#define ngx_http_lua_probe_info(msg) +#endif + + static int ngx_http_lua_uthread_spawn(lua_State *L); static int ngx_http_lua_uthread_wait(lua_State *L); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1a1b129373..76a177eee8 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -41,10 +41,8 @@ #include "ngx_http_lua_uthread.h" -#if 0 -#ifdef ngx_http_lua_probe_info +#if 1 #undef ngx_http_lua_probe_info -#endif #define ngx_http_lua_probe_info(msg) #endif From 0263ef747cb510cba5a909e68fdb447a52d9be36 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 11:15:11 -0700 Subject: [PATCH 0119/2239] feature: ngx.req.get_headers() now takes a second (optional) boolean argument that can be used to convert all header names into the lowercase form. thanks James Hurst and Matthieu Tourne for proposing this feature. --- src/ngx_http_lua_headers.c | 29 +++++++++++++++++++++-------- t/028-req-header.t | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index cccb12b630..b02ebe77bb 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -25,17 +25,23 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { ngx_uint_t i; int n; int max; + int lowcase = 0; int count = 0; n = lua_gettop(L); - if (n != 0 && n != 1) { - return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); - } + if (n >= 1) { + if (lua_isnil(L, 1)) { + max = NGX_HTTP_LUA_MAX_HEADERS; - if (n == 1) { - max = luaL_checkinteger(L, 1); - lua_pop(L, 1); + } else { + max = luaL_checkinteger(L, 1); + lua_pop(L, 1); + } + + if (n >= 2) { + lowcase = lua_toboolean(L, 2); + } } else { max = NGX_HTTP_LUA_MAX_HEADERS; @@ -67,8 +73,15 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { i = 0; } - lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); - /* stack: table key */ + if (lowcase) { + lua_pushlstring(L, (char *) header[i].lowcase_key, + header[i].key.len); + + } else { + lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); + } + + /* stack: table key */ lua_pushlstring(L, (char *) header[i].value.data, header[i].value.len); /* stack: table key value */ diff --git a/t/028-req-header.t b/t/028-req-header.t index 8af7ada4d9..fe3f03434a 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -731,3 +731,26 @@ Foo21: foo21\r Foo22: foo22\r / + + +=== TEST 27: iterating through headers (lowercase) +--- config + location /t { + content_by_lua ' + local h = {} + for k, v in pairs(ngx.req.get_headers(nil, true)) do + ngx.say(k, ": ", v) + end + '; + } +--- request +GET /t +--- more_headers +Foo: bar +Bar: baz +--- response_body +host: localhost +bar: baz +foo: bar +connection: Close + From b09f1578449da8ef63c82b363b9e499cee8b193e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 11:42:05 -0700 Subject: [PATCH 0120/2239] feature: when the lowercase argument to ngx.req.get_headers() is true, then any keys like "My-Header-Name" and "my_header_name" will be able to index the "my-header-name" entry in the Lua table returned. (behind the scene, we ngx.req.get_headers() just adds a __index metamethod to the resulting table when the lowercase argument is true.) thanks Matthieu Tourne for the proposal. --- src/ngx_http_lua_headers.c | 36 +++++++++++++++++++++++++++++++++++- src/ngx_http_lua_headers.h | 2 +- src/ngx_http_lua_util.c | 3 ++- src/ngx_http_lua_util.h | 3 +++ t/028-req-header.t | 21 +++++++++++++++++++-- 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index b02ebe77bb..f5f6c2abc4 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -58,6 +58,12 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { lua_createtable(L, 0, 4); + if (lowcase) { + lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + } + part = &r->headers_in.headers.part; header = part->elts; @@ -445,8 +451,10 @@ ngx_http_lua_inject_resp_header_api(lua_State *L) void -ngx_http_lua_inject_req_header_api(lua_State *L) +ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) { + int rc; + lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear); lua_setfield(L, -2, "clear_header"); @@ -455,5 +463,31 @@ ngx_http_lua_inject_req_header_api(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" + "key = string.gsub(string.lower(key), '_', '-')\n" + "return tb[key]"; + + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, + "ngx.req.get_headers __index"); + } + + 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)); + + lua_pop(L, 3); + return; + } + + lua_setfield(L, -2, "__index"); + + lua_rawset(L, LUA_REGISTRYINDEX); } diff --git a/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h index 61db08292f..b086d6fd9f 100644 --- a/src/ngx_http_lua_headers.h +++ b/src/ngx_http_lua_headers.h @@ -6,7 +6,7 @@ void ngx_http_lua_inject_resp_header_api(lua_State *L); -void ngx_http_lua_inject_req_header_api(lua_State *L); +void ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L); #endif /* NGX_HTTP_LUA_HEADERS_H */ diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index e07effe314..8692a70d89 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -45,6 +45,7 @@ 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_req_get_headers_metatable_key; /* coroutine anchoring table key in Lua vm registry */ @@ -1745,7 +1746,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) lua_createtable(L, 0 /* narr */, 20 /* nrec */); /* .req */ - ngx_http_lua_inject_req_header_api(L); + ngx_http_lua_inject_req_header_api(log, L); ngx_http_lua_inject_req_uri_api(log, L); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 7a35a25126..19555db6e1 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -35,6 +35,9 @@ 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; +extern char ngx_http_lua_req_get_headers_metatable_key; + + #ifndef ngx_str_set #define ngx_str_set(str, text) \ (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text diff --git a/t/028-req-header.t b/t/028-req-header.t index fe3f03434a..9f75ed8c48 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -746,11 +746,28 @@ Foo22: foo22\r --- request GET /t --- more_headers -Foo: bar +My-Foo: bar Bar: baz --- response_body host: localhost bar: baz -foo: bar +my-foo: bar connection: Close + + +=== TEST 28: __index metamethod +--- config + location /t { + content_by_lua ' + local h = ngx.req.get_headers(nil, true) + ngx.say("My-Foo-Header: ", h.my_foo_header) + '; + } +--- request +GET /t +--- more_headers +My-Foo-Header: Hello World +--- response_body +My-Foo-Header: Hello World + From a90cc0d99e3b1b4507c1f2c180346cc3426a7ee1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 12:23:20 -0700 Subject: [PATCH 0121/2239] feature: now ngx.req.get_headers() will return a table with keys in all lowercase by default. made the second argument be "raw". when the "raw" argument is true, the header names will be the original form. --- src/ngx_http_lua_headers.c | 23 ++++++++++-------- t/028-req-header.t | 50 ++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index f5f6c2abc4..0ea54eda97 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -25,7 +25,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { ngx_uint_t i; int n; int max; - int lowcase = 0; + int raw = 0; int count = 0; n = lua_gettop(L); @@ -40,7 +40,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { } if (n >= 2) { - lowcase = lua_toboolean(L, 2); + raw = lua_toboolean(L, 2); } } else { @@ -58,7 +58,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { lua_createtable(L, 0, 4); - if (lowcase) { + if (!raw) { lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -69,6 +69,8 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { for (i = 0; /* void */; i++) { + dd("stack top: %d", lua_gettop(L)); + if (i >= part->nelts) { if (part->next == NULL) { break; @@ -79,12 +81,12 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { i = 0; } - if (lowcase) { - lua_pushlstring(L, (char *) header[i].lowcase_key, - header[i].key.len); + if (raw) { + lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); } else { - lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); + lua_pushlstring(L, (char *) header[i].lowcase_key, + header[i].key.len); } /* stack: table key */ @@ -372,7 +374,8 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) } else { for (i = 1; i <= n; i++) { - dd("header value table index %d", (int) i); + dd("header value table index %d, top: %d", (int) i, + lua_gettop(L)); lua_rawgeti(L, 2, i); p = (u_char *) luaL_checklstring(L, -1, &len); @@ -470,8 +473,8 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) { const char buf[] = "local tb, key = ...\n" - "key = string.gsub(string.lower(key), '_', '-')\n" - "return tb[key]"; + "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"); diff --git a/t/028-req-header.t b/t/028-req-header.t index 9f75ed8c48..c483a6ca70 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -42,7 +42,7 @@ Bar: baz location /req-header { content_by_lua ' local h = {} - for k, v in pairs(ngx.req.get_headers()) do + for k, v in pairs(ngx.req.get_headers(nil, true)) do h[k] = v end ngx.say("Foo: ", h["Foo"] or "nil") @@ -301,6 +301,7 @@ GET /bar } --- more_headers Foo: foo + --- request GET /foo --- response_body @@ -412,11 +413,11 @@ $s my @k; my $i = 1; while ($i <= 98) { - push @k, "X-$i"; + push @k, "x-$i"; $i++; } -push @k, "Connection: Close\n"; -push @k, "Host: localhost\n"; +push @k, "connection: Close\n"; +push @k, "host: localhost\n"; @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { @@ -460,11 +461,11 @@ $s my @k; my $i = 1; while ($i <= 100) { - push @k, "X-$i"; + push @k, "x-$i"; $i++; } -push @k, "Connection: Close\n"; -push @k, "Host: localhost\n"; +push @k, "connection: Close\n"; +push @k, "host: localhost\n"; @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { @@ -508,11 +509,11 @@ $s my @k; my $i = 1; while ($i <= 105) { - push @k, "X-$i"; + push @k, "x-$i"; $i++; } -push @k, "Connection: Close\n"; -push @k, "Host: localhost\n"; +push @k, "connection: Close\n"; +push @k, "host: localhost\n"; @k = sort @k; for my $k (@k) { if ($k =~ /\d+/) { @@ -733,7 +734,7 @@ Foo22: foo22\r -=== TEST 27: iterating through headers (lowercase) +=== TEST 27: iterating through headers (raw form) --- config location /t { content_by_lua ' @@ -749,14 +750,14 @@ GET /t My-Foo: bar Bar: baz --- response_body -host: localhost -bar: baz -my-foo: bar -connection: Close +Host: localhost +Bar: baz +My-Foo: bar +Connection: Close -=== TEST 28: __index metamethod +=== TEST 28: __index metamethod not working for "raw" mode --- config location /t { content_by_lua ' @@ -769,5 +770,22 @@ GET /t --- more_headers My-Foo-Header: Hello World --- response_body +My-Foo-Header: nil + + + +=== TEST 29: __index metamethod not working for the default mode +--- config + location /t { + content_by_lua ' + local h = ngx.req.get_headers() + ngx.say("My-Foo-Header: ", h.my_foo_header) + '; + } +--- request +GET /t +--- more_headers +My-Foo-Header: Hello World +--- response_body My-Foo-Header: Hello World From beb2bfff4d50eb60481baeea714e66989fb9b287 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 14:50:06 -0700 Subject: [PATCH 0122/2239] updated docs to reflect recent changes in ngx.req.get_headers(). --- README | 20 +++++++++++++++++++- README.markdown | 14 +++++++++++++- doc/HttpLuaModule.wiki | 14 +++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/README b/README index 73643fcddf..6f41b2e403 100644 --- a/README +++ b/README @@ -2360,7 +2360,7 @@ Nginx API for Lua Removing the "max_args" cap is strongly discouraged. ngx.req.get_headers - syntax: *headers = ngx.req.get_headers(max_headers?)* + syntax: *headers = ngx.req.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** @@ -2408,6 +2408,24 @@ Nginx API for Lua Removing the "max_headers" cap is strongly discouraged. + Since the 0.6.9 release, all the header names in the Lua table returned + are converted to the pure lower-case form by default, unless the "raw" + argument is set to "true" (default to "false"). + + Also, by default, an "__index" metamethod is added automatically to the + resulting Lua table that will normalize the keys to the pure lower-case + form with all underscores converted to dashes in case of a lookup miss. + For example, if a request header "My-Foo-Header" is present, then the + following invocations will all pick up the value of this header + correctly: + + ngx.say(headers.my_foo_header) + ngx.say(headers["My-Foo-Header"]) + ngx.say(headers["my-foo-header"]) + + The "__index" metamethod will not be added when the "raw" argument is + set to "true". + ngx.req.set_header syntax: *ngx.req.set_header(header_name, header_value)* diff --git a/README.markdown b/README.markdown index 9f2e65532c..2258d4fa8b 100644 --- a/README.markdown +++ b/README.markdown @@ -2216,7 +2216,7 @@ Removing the `max_args` cap is strongly discouraged. ngx.req.get_headers ------------------- -**syntax:** *headers = ngx.req.get_headers(max_headers?)* +**syntax:** *headers = ngx.req.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** @@ -2267,6 +2267,18 @@ This argument can be set to zero to remove the limit and to process all request Removing the `max_headers` cap is strongly discouraged. +Since the `0.6.9` release, all the header names in the Lua table returned are converted to the pure lower-case form by default, unless the `raw` argument is set to `true` (default to `false`). + +Also, by default, an `__index` metamethod is added automatically to the resulting Lua table that will normalize the keys to the pure lower-case form with all underscores converted to dashes in case of a lookup miss. For example, if a request header `My-Foo-Header` is present, then the following invocations will all pick up the value of this header correctly: + + + ngx.say(headers.my_foo_header) + ngx.say(headers["My-Foo-Header"]) + ngx.say(headers["my-foo-header"]) + + +The `__index` metamethod will not be added when the `raw` argument is set to `true`. + ngx.req.set_header ------------------ **syntax:** *ngx.req.set_header(header_name, header_value)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 7a0e5c015e..f03943965c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2151,7 +2151,7 @@ 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_headers == -'''syntax:''' ''headers = ngx.req.get_headers(max_headers?)'' +'''syntax:''' ''headers = ngx.req.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*'' @@ -2202,6 +2202,18 @@ This argument can be set to zero to remove the limit and to process all request Removing the max_headers cap is strongly discouraged. +Since the 0.6.9 release, all the header names in the Lua table returned are converted to the pure lower-case form by default, unless the raw argument is set to true (default to false). + +Also, by default, an __index metamethod is added automatically to the resulting Lua table that will normalize the keys to the pure lower-case form with all underscores converted to dashes in case of a lookup miss. For example, if a request header My-Foo-Header is present, then the following invocations will all pick up the value of this header correctly: + + + ngx.say(headers.my_foo_header) + ngx.say(headers["My-Foo-Header"]) + ngx.say(headers["my-foo-header"]) + + +The __index metamethod will not be added when the raw argument is set to true. + == ngx.req.set_header == '''syntax:''' ''ngx.req.set_header(header_name, header_value)'' From a30c2d83130d335f030df6ad8378097b9c22cb5d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 18:02:46 -0700 Subject: [PATCH 0123/2239] made a test case less possible to fail unexpectedly in slow testing mode. --- t/005-exit.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/005-exit.t b/t/005-exit.t index 7025ad6661..c78d402e36 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -345,6 +345,7 @@ GET /api?uid=32 Logged in 56 --- no_error_log [error] +--- timeout: 5 From 0f66b1b3379d5b1261ad8c6f24310e748ca151bc Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 2 Oct 2012 18:08:01 -0700 Subject: [PATCH 0124/2239] bumped version to 0.6.9. --- README | 6 +++--- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README b/README index 6f41b2e403..db8995c706 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.6.8 - () released on 28 - September 2012. + This document describes ngx_lua v0.6.9 + () released on 2 + October 2012. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): diff --git a/README.markdown b/README.markdown index 2258d4fa8b..d4ceca9207 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.6.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 28 September 2012. +This document describes ngx_lua [v0.6.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 2 October 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f03943965c..a824b4c7c6 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.6.8] released on 28 September 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.9] released on 2 October 2012. = Synopsis = From 7fc1dc720fa47bb441127f3a62b768acb5afdae3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 3 Oct 2012 10:58:17 -0700 Subject: [PATCH 0125/2239] fixed a compilation warning in the cosocket code from some old gcc. thanks Dirk Feytons for reporting this issue as as #162. --- src/ngx_http_lua_socket_tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 84f9b908d0..7ef85ed466 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2606,7 +2606,9 @@ ngx_http_lua_socket_read_until(void *data, ssize_t bytes) u_char *pat; size_t pat_len; int i; - int state, old_state; + int state; + int old_state = 0; /* just to make old + gcc happy */ ngx_http_lua_dfa_edge_t *edge; unsigned matched; ngx_int_t rc; From ea456890a5400a44fb6b30759184e9626e121353 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 3 Oct 2012 18:15:02 -0700 Subject: [PATCH 0126/2239] feature: added public C API ngx_http_shared_dict_get and ngx_http_lua_find_zone as per Piotr Sikora's request. --- src/api/ngx_http_lua_api.h | 17 +++++ src/ngx_http_lua_shdict.c | 136 +++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 6 deletions(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 767f89b86a..2cb6be29ea 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -11,6 +11,18 @@ /* Public API for other Nginx modules */ +typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + lua_Number n; /* number */ + ngx_str_t s; /* string */ + } value; + +} ngx_http_lua_value_t; + + lua_State * ngx_http_lua_get_global_state(ngx_conf_t *cf); ngx_http_request_t * ngx_http_lua_get_request(lua_State *L); @@ -18,6 +30,11 @@ ngx_http_request_t * 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); +ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, + u_char *key_data, size_t key_len, ngx_http_lua_value_t *value); + +ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); + #endif /* NGX_HTTP_LUA_API_H */ diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index fe1c59beba..74fa9e7475 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -7,6 +7,7 @@ #include "ngx_http_lua_shdict.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_conf.h" +#include "ngx_http_lua_api.h" static int ngx_http_lua_shdict_set(lua_State *L); @@ -395,8 +396,7 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_http_lua_shdict_expire(ctx, 1); #endif - rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, - &sd); + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returns %d", (int) rc); @@ -747,8 +747,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) ngx_http_lua_shdict_expire(ctx, 1); #endif - rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, - &sd); + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); @@ -997,8 +996,7 @@ ngx_http_lua_shdict_incr(lua_State *L) ngx_http_lua_shdict_expire(ctx, 1); #endif - rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, - &sd); + rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); @@ -1040,3 +1038,129 @@ ngx_http_lua_shdict_incr(lua_State *L) return 2; } + +ngx_int_t +ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, + size_t key_len, ngx_http_lua_value_t *value) +{ + u_char *data; + size_t len; + uint32_t hash; + ngx_int_t rc; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + hash = ngx_crc32_short(key_data, key_len); + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_http_lua_shdict_lookup(zone, hash, key_data, key_len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return rc; + } + + /* rc == NGX_OK */ + + value->type = sd->value_type; + + data = sd->data + sd->key_len; + len = (size_t) sd->value_len; + + switch (value->type) { + case LUA_TSTRING: + + 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"); + return NGX_ERROR; + } + + if (len > value->value.s.len) { + len = value->value.s.len; + + } else { + value->value.s.len = len; + } + + ngx_memcpy(value->value.s.data, data, len); + break; + + case LUA_TNUMBER: + + if (len != sizeof(lua_Number)) { + 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); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + + ngx_memcpy(&value->value.b, data, len); + break; + + case LUA_TBOOLEAN: + + if (len != sizeof(u_char)) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean value " + "size found for key %*s: %lu", key_len, key_data, + (unsigned long) len); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type " + "found for key %*s: %d", key_data, key_len, + (int) value->type); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_shm_zone_t * +ngx_http_lua_find_zone(u_char *name_data, size_t name_len) +{ + ngx_str_t *name; + ngx_uint_t i; + ngx_shm_zone_t *zone; + volatile ngx_list_part_t *part; + + part = &ngx_cycle->shared_memory.part; + zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + zone = part->elts; + i = 0; + } + + name = &zone[i].shm.name; + + if (name->len == name_len + && ngx_strncmp(name->data, name_data, name_len) == 0) + { + return zone; + } + } + + return NULL; +} + From cc5d928cb4bc6ef18ced670f68e736a47110d22d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Oct 2012 12:22:04 -0700 Subject: [PATCH 0127/2239] renamed ngx_http_lua_shared_dict_lookup to ngx_http_lua_shared_dict_get; fixed various issues in this public C function. also added tests for it. --- src/ngx_http_lua_shdict.c | 29 ++- t/099-c-api.t | 360 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 381 insertions(+), 8 deletions(-) create mode 100644 t/099-c-api.t diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 74fa9e7475..90c99e3d23 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1040,7 +1040,7 @@ ngx_http_lua_shdict_incr(lua_State *L) ngx_int_t -ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, +ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, size_t key_len, ngx_http_lua_value_t *value) { u_char *data; @@ -1050,6 +1050,10 @@ ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; + if (zone == NULL) { + return NGX_ERROR; + } + hash = ngx_crc32_short(key_data, key_len); ctx = zone->data; @@ -1070,6 +1074,8 @@ ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, value->type = sd->value_type; + dd("type: %d", (int) value->type); + data = sd->data + sd->key_len; len = (size_t) sd->value_len; @@ -1095,9 +1101,9 @@ ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, case LUA_TNUMBER: if (len != sizeof(lua_Number)) { - 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); + 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); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; @@ -1109,23 +1115,27 @@ ngx_http_lua_shared_dict_lookup(ngx_shm_zone_t *zone, u_char *key_data, case LUA_TBOOLEAN: if (len != sizeof(u_char)) { - ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean value " - "size found for key %*s: %lu", key_len, key_data, - (unsigned long) len); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean " + "value size found for key %*s: %lu", key_len, + key_data, (unsigned long) len); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } + value->value.b = *data; + break; + default: ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type " - "found for key %*s: %d", key_data, key_len, + "found for key %*s: %d", key_len, key_data, (int) value->type); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } + ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } @@ -1154,6 +1164,9 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) name = &zone[i].shm.name; + dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len); + dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len); + if (name->len == name_len && ngx_strncmp(name->data, name_data, name_len) == 0) { diff --git a/t/099-c-api.t b/t/099-c-api.t new file mode 100644 index 0000000000..94ee13f6d4 --- /dev/null +++ b/t/099-c-api.t @@ -0,0 +1,360 @@ +# 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() * (blocks() * 3); + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: find zone +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + void *ngx_http_lua_find_zone(char *data, size_t len); + ]] + + local buf = ffi.new("char[?]", 4) + ffi.copy(buf, "foo") + local zone = ffi.C.ngx_http_lua_find_zone(buf, 3) + ngx.say("foo zone: ", tonumber(ffi.cast("long", zone)) ~= 0 and "defined" or "undef") + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + ngx.say("dogs zone: ", tonumber(ffi.cast("long", zone)) ~= 0 and "defined" or "undef") + '; + } +--- request +GET /test +--- response_body +foo zone: undef +dogs zone: defined +--- no_error_log +[error] + + + +=== TEST 2: number typed value +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + typedef struct { + size_t len; + char *data; + } ngx_str_t; + + typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + double n; /* number */ + ngx_str_t s; /* string */ + } value; + + } ngx_http_lua_value_t; + + void *ngx_http_lua_find_zone(char *data, size_t len); + intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); + ]] + + local dogs = ngx.shared.dogs + dogs:set("foo", 1234567) + dogs:set("bar", 3.14159) + + local buf = ffi.new("char[?]", 4) + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + + ffi.copy(buf, "foo") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("foo: rc=", tonumber(rc), + ", type=", val[0].type, + ", val=", tonumber(val[0].value.n)) + + ffi.copy(buf, "bar") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("bar: rc=", tonumber(rc), + ", type=", val[0].type, + ", val=", tonumber(val[0].value.n)) + '; + } +--- request +GET /test +--- response_body +foo: rc=0, type=3, val=1234567 +bar: rc=0, type=3, val=3.14159 +--- no_error_log +[error] + + + +=== TEST 3: boolean typed value +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + typedef struct { + size_t len; + char *data; + } ngx_str_t; + + typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + double n; /* number */ + ngx_str_t s; /* string */ + } value; + + } ngx_http_lua_value_t; + + void *ngx_http_lua_find_zone(char *data, size_t len); + intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); + ]] + + local dogs = ngx.shared.dogs + dogs:set("foo", true) + dogs:set("bar", false) + + local buf = ffi.new("char[?]", 4) + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + + ffi.copy(buf, "foo") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("foo: rc=", tonumber(rc), + ", type=", tonumber(val[0].type), + ", val=", tonumber(val[0].value.b)) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + ffi.copy(buf, "bar") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("bar: rc=", tonumber(rc), + ", type=", tonumber(val[0].type), + ", val=", tonumber(val[0].value.b)) + '; + } +--- request +GET /test +--- response_body +foo: rc=0, type=1, val=1 +bar: rc=0, type=1, val=0 +--- no_error_log +[error] + + + +=== TEST 4: key not found +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + typedef struct { + size_t len; + char *data; + } ngx_str_t; + + typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + double n; /* number */ + ngx_str_t s; /* string */ + } value; + + } ngx_http_lua_value_t; + + void *ngx_http_lua_find_zone(char *data, size_t len); + intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); + ]] + + local buf = ffi.new("char[?]", 4) + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + + ffi.copy(buf, "foo") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("foo: rc=", tonumber(rc)) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + ffi.copy(buf, "bar") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("bar: rc=", tonumber(rc)) + '; + } +--- request +GET /test +--- response_body +foo: rc=-5 +bar: rc=-5 +--- no_error_log +[error] + + + +=== TEST 5: string typed value +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + typedef struct { + size_t len; + char *data; + } ngx_str_t; + + typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + double n; /* number */ + ngx_str_t s; /* string */ + } value; + + } ngx_http_lua_value_t; + + void *ngx_http_lua_find_zone(char *data, size_t len); + intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); + ]] + + local dogs = ngx.shared.dogs + dogs:set("foo", "hello world") + dogs:set("bar", "") + + local buf = ffi.new("char[?]", 4) + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + + local s = ffi.new("char[?]", 20) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + val[0].value.s.len = 20 + val[0].value.s.data = s + + ffi.copy(buf, "foo") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("foo: rc=", tonumber(rc), + ", type=", tonumber(val[0].type), + ", val=", ffi.string(val[0].value.s.data, val[0].value.s.len), + ", len=", tonumber(val[0].value.s.len)) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + val[0].value.s.len = 20 + val[0].value.s.data = s + + ffi.copy(buf, "bar") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("bar: rc=", tonumber(rc), + ", type=", tonumber(val[0].type), + ", val=", ffi.string(val[0].value.s.data, val[0].value.s.len), + ", len=", tonumber(val[0].value.s.len)) + '; + } +--- request +GET /test +--- response_body +foo: rc=0, type=4, val=hello world, len=11 +bar: rc=0, type=4, val=, len=0 +--- no_error_log +[error] + + + +=== TEST 6: nil typed value +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /test { + content_by_lua ' + local ffi = require "ffi" + + ffi.cdef[[ + typedef struct { + size_t len; + char *data; + } ngx_str_t; + + typedef struct { + uint8_t type; + + union { + int b; /* boolean */ + double n; /* number */ + ngx_str_t s; /* string */ + } value; + + } ngx_http_lua_value_t; + + void *ngx_http_lua_find_zone(char *data, size_t len); + intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); + ]] + + local dogs = ngx.shared.dogs + dogs:set("foo", nil) + + local buf = ffi.new("char[?]", 4) + + ffi.copy(buf, "dogs") + zone = ffi.C.ngx_http_lua_find_zone(buf, 4) + + local val = ffi.new("ngx_http_lua_value_t[?]", 1) + + ffi.copy(buf, "foo") + local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) + ngx.say("foo: rc=", tonumber(rc)) + '; + } +--- request +GET /test +--- response_body +foo: rc=-5 +--- no_error_log +[error] + From 95b2761743c465abbcbf892aa0af56330c1c36d9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 4 Oct 2012 19:19:52 -0700 Subject: [PATCH 0128/2239] fixed a test case using shdict for the "use hup" testing mode. --- t/099-c-api.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/099-c-api.t b/t/099-c-api.t index 94ee13f6d4..93e10089b8 100644 --- a/t/099-c-api.t +++ b/t/099-c-api.t @@ -207,6 +207,9 @@ bar: rc=0, type=1, val=0 intptr_t ngx_http_lua_shared_dict_get(void *zone, char *kdata, size_t klen, ngx_http_lua_value_t *val); ]] + local dogs = ngx.shared.dogs + dogs:flush_all() + local buf = ffi.new("char[?]", 4) ffi.copy(buf, "dogs") From d3f55d7a7c421bc51e019dfba465b59ab1b93b22 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 5 Oct 2012 19:11:43 +0000 Subject: [PATCH 0129/2239] bugfix: ffi.copy() was used incorrectly in the test cases in 099-c-api.t: it might write out of the buffer. this issue was caught by valgrind on linux i386. --- t/099-c-api.t | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/t/099-c-api.t b/t/099-c-api.t index 93e10089b8..28b35eaf4f 100644 --- a/t/099-c-api.t +++ b/t/099-c-api.t @@ -6,7 +6,7 @@ use Test::Nginx::Socket; #master_process_enabled(1); log_level('warn'); -repeat_each(2); +repeat_each(3); plan tests => repeat_each() * (blocks() * 3); @@ -32,11 +32,11 @@ __DATA__ ]] local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local zone = ffi.C.ngx_http_lua_find_zone(buf, 3) ngx.say("foo zone: ", tonumber(ffi.cast("long", zone)) ~= 0 and "defined" or "undef") - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) ngx.say("dogs zone: ", tonumber(ffi.cast("long", zone)) ~= 0 and "defined" or "undef") '; @@ -86,18 +86,18 @@ dogs zone: defined local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("foo: rc=", tonumber(rc), ", type=", val[0].type, ", val=", tonumber(val[0].value.n)) - ffi.copy(buf, "bar") + ffi.copy(buf, "bar", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("bar: rc=", tonumber(rc), ", type=", val[0].type, @@ -149,19 +149,19 @@ bar: rc=0, type=3, val=3.14159 local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("foo: rc=", tonumber(rc), ", type=", tonumber(val[0].type), ", val=", tonumber(val[0].value.b)) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "bar") + ffi.copy(buf, "bar", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("bar: rc=", tonumber(rc), ", type=", tonumber(val[0].type), @@ -212,17 +212,17 @@ bar: rc=0, type=1, val=0 local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("foo: rc=", tonumber(rc)) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "bar") + ffi.copy(buf, "bar", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("bar: rc=", tonumber(rc)) '; @@ -272,7 +272,7 @@ bar: rc=-5 local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local s = ffi.new("char[?]", 20) @@ -281,7 +281,7 @@ bar: rc=-5 val[0].value.s.len = 20 val[0].value.s.data = s - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("foo: rc=", tonumber(rc), ", type=", tonumber(val[0].type), @@ -292,7 +292,7 @@ bar: rc=-5 val[0].value.s.len = 20 val[0].value.s.data = s - ffi.copy(buf, "bar") + ffi.copy(buf, "bar", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("bar: rc=", tonumber(rc), ", type=", tonumber(val[0].type), @@ -344,12 +344,12 @@ bar: rc=0, type=4, val=, len=0 local buf = ffi.new("char[?]", 4) - ffi.copy(buf, "dogs") + ffi.copy(buf, "dogs", 4) zone = ffi.C.ngx_http_lua_find_zone(buf, 4) local val = ffi.new("ngx_http_lua_value_t[?]", 1) - ffi.copy(buf, "foo") + ffi.copy(buf, "foo", 3) local rc = ffi.C.ngx_http_lua_shared_dict_get(zone, buf, 3, val) ngx.say("foo: rc=", tonumber(rc)) '; From 73d8dd231b26da46e57fb599f480407036b47193 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 5 Oct 2012 19:48:53 -0700 Subject: [PATCH 0130/2239] bumped version to 0.6.10. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index db8995c706..1ad4a14973 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.6.9 - () released on 2 + This document describes ngx_lua v0.6.10 + () released on 5 October 2012. Synopsis diff --git a/README.markdown b/README.markdown index d4ceca9207..69c45a1e8c 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.6.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 2 October 2012. +This document describes ngx_lua [v0.6.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 5 October 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a824b4c7c6..f24b01fed6 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.6.9] released on 2 October 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.6.10] released on 5 October 2012. = Synopsis = From 2694d7758c6dfe6f7fe98aeb799abb3a9a068124 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 9 Oct 2012 12:22:07 -0700 Subject: [PATCH 0131/2239] bugfix: older gcc versions might issue warnings like "variable 'nrets' might be clobbered by 'longjmp' or 'vfork'", like gcc 3.4.3 for Solaris 11. thanks Wenhua Zhang for reporting this issue. --- src/ngx_http_lua_util.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index e243daf969..5513feca37 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -939,22 +939,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_int_t rc; #if (NGX_PCRE) ngx_pool_t *old_pool = NULL; - unsigned pcre_pool_resumed = 1; #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread, top:%d", lua_gettop(L)); - if (ctx->cur_co_ctx->thread_spawn_yielded) { - ngx_http_lua_probe_info("thread spawn yielded"); - - ctx->cur_co_ctx->thread_spawn_yielded = 0; - nrets = 1; - - } else { - nrets = nret; - } - /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); @@ -962,6 +951,16 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, NGX_LUA_EXCEPTION_TRY { + if (ctx->cur_co_ctx->thread_spawn_yielded) { + ngx_http_lua_probe_info("thread spawn yielded"); + + 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, @@ -970,7 +969,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); - pcre_pool_resumed = 0; #endif /* run code */ @@ -982,7 +980,6 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ ngx_http_lua_pcre_malloc_done(old_pool); - pcre_pool_resumed = 1; #endif #if 0 @@ -1379,15 +1376,7 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, } } NGX_LUA_EXCEPTION_CATCH { - dd("nginx execution restored"); - -#if (NGX_PCRE) - if (!pcre_pool_resumed) { - ngx_http_lua_pcre_malloc_done(old_pool); - } -#endif - } return NGX_ERROR; From 5d0fb9feaeb653e70b0c2d97ddfea40c1db24c80 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 9 Oct 2012 22:41:59 -0700 Subject: [PATCH 0132/2239] bugfix: the lua light threads would leak in case of nginx filter finalization. this issue was caught by the "check leak" testing mode provided by Test::Nginx while running on Amazon EC2. --- src/ngx_http_lua_util.c | 25 +++++++++++++++++++++++++ t/072-conditional-get.t | 14 ++++++++++++-- t/StapThread.pm | 11 +++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 5513feca37..8f34a48e1d 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -882,6 +882,7 @@ ngx_http_lua_request_cleanup(void *data) /* force coroutine handling the request quit */ if (ctx == NULL) { + dd("ctx is NULL"); return; } @@ -1332,6 +1333,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, /* being the entry thread aborted */ + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ngx_http_lua_request_cleanup(r); dd("headers sent? %d", ctx->headers_sent ? 1 : 0); @@ -1385,6 +1390,11 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, lua_settop(L, 0); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ngx_http_lua_request_cleanup(r); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua handler aborted: " @@ -1976,6 +1986,11 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ngx_http_lua_request_cleanup(r); if (ctx->exec_uri.data[0] == '@') { @@ -2061,6 +2076,11 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ngx_http_lua_request_cleanup(r); if ((ctx->exit_code == NGX_OK @@ -2318,6 +2338,11 @@ ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r, ngx_http_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 1); ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_DEAD; + + if (r->filter_finalize) { + ngx_http_set_ctx(r, ctx, ngx_http_lua_module); + } + ngx_http_lua_request_cleanup(r); return NGX_OK; diff --git a/t/072-conditional-get.t b/t/072-conditional-get.t index e6867da5cc..285fe14dd8 100644 --- a/t/072-conditional-get.t +++ b/t/072-conditional-get.t @@ -1,6 +1,10 @@ # 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(); @@ -8,9 +12,8 @@ use Test::Nginx::Socket; #log_level('warn'); repeat_each(2); -#repeat_each(1); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 1); #no_diff(); #no_long_string(); @@ -70,6 +73,13 @@ If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT GET /lua --- more_headers If-Unmodified-Since: Thu, 10 May 2012 07:50:47 GMT + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +delete thread 1 + --- response_body_like: 412 Precondition Failed --- error_code: 412 --- error_log diff --git a/t/StapThread.pm b/t/StapThread.pm index 9ae579e68b..25290144b2 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -203,12 +203,23 @@ F(ngx_http_lua_sleep_resume) { M(http-lua-coroutine-done) { t = gen_id($arg2) printf("terminate coro %d: %s\n", t, $arg3 ? "ok" : "fail") + //print_ubacktrace() } +F(ngx_http_lua_ngx_echo) { + println("ngx.print or ngx.say") +} + +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) } +*/ F(ngx_http_lua_uthread_wait) { t = gen_id($L) From 4d8cbe95cd97526723d9f637c2c50194172cc826 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 9 Oct 2012 22:55:26 -0700 Subject: [PATCH 0133/2239] fixed those test cases using the UDP cosockets to be prepared for data read in a single run (without EAGAIN, that is). --- t/023-rewrite/uthread-spawn.t | 20 ++++++++++++++++---- t/024-access/uthread-spawn.t | 20 ++++++++++++++++---- t/093-uthread-spawn.t | 19 +++++++++++++++---- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index 9af29d6f80..1ddee930d3 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1054,8 +1054,8 @@ received: OK GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript ---- stap_out -create 2 in 1 +--- stap_out_like chop +^(?:create 2 in 1 spawn user thread 2 in 1 terminate 1: ok delete thread 1 @@ -1063,14 +1063,26 @@ 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)$ --- udp_listen: 12345 --- udp_query: blah --- udp_reply: hello udp ---- response_body -before +--- response_body_like chop +^(?:before after received: hello udp +|before +received: hello udp +after)$ + --- no_error_log [error] diff --git a/t/024-access/uthread-spawn.t b/t/024-access/uthread-spawn.t index ed90869798..50f3c8cfbe 100644 --- a/t/024-access/uthread-spawn.t +++ b/t/024-access/uthread-spawn.t @@ -1054,8 +1054,8 @@ received: OK GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript ---- stap_out -create 2 in 1 +--- stap_out_like chop +^(?:create 2 in 1 spawn user thread 2 in 1 terminate 1: ok delete thread 1 @@ -1063,14 +1063,26 @@ 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)$ --- udp_listen: 12345 --- udp_query: blah --- udp_reply: hello udp ---- response_body -before +--- response_body_like chop +^(?:before after received: hello udp +|before +received: hello udp +after)$ + --- no_error_log [error] diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index e2aa1fc525..caf4a2a9f0 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -982,21 +982,32 @@ received: OK GET /lua --- stap2 eval: $::StapScript --- stap eval: $::GCScript ---- stap_out -create 2 in 1 +--- stap_out_like chop +^(?:create 2 in 1 spawn user thread 2 in 1 terminate 1: ok delete thread 1 terminate 2: ok delete thread 2 +|create 2 in 1 +spawn user thread 2 in 1 +terminate 2: ok +terminate 1: ok +delete thread 2 +delete thread 1 +)$ --- udp_listen: 12345 --- udp_query: blah --- udp_reply: hello udp ---- response_body -before +--- response_body_like chop +^(?:before after received: hello udp +|before +received: hello udp +after)$ + --- no_error_log [error] From 1690add7f89911807dad1e5a424a6f05576dcafe Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 10 Oct 2012 15:06:25 -0700 Subject: [PATCH 0134/2239] docs: added a warning for ngx.var.VARIABLE that memory is allocated in the per-request memory pool. also made it clear why "return" is recommended to be used with ngx.exit(). thanks Antoine. --- README | 17 +++++++++++++++-- README.markdown | 11 ++++++++++- doc/HttpLuaModule.wiki | 11 ++++++++++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README b/README index 1ad4a14973..fc103c3a9f 100644 --- a/README +++ b/README @@ -1416,6 +1416,18 @@ Nginx API for Lua ngx.var.args = nil + WARNING When reading from an Nginx variable, Nginx will allocate memory + in the per-request memory pool which is freed only at request + termination. So when you need to read from an Nginx variable repeatedly + in your Lua code, cache the Nginx variable value to your own Lua + variable, for example, + + local val = ngx.var.some_var + --- use the val repeatedly later + + 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, @@ -3031,8 +3043,9 @@ Nginx API for Lua Note that while this method accepts all HTTP status constants as input, it only accepts "NGX_OK" and "NGX_ERROR" of the core constants. - It is strongly recommended to combine the "return" statement with this - call, i.e., "return ngx.exit(...)". + 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()* diff --git a/README.markdown b/README.markdown index 69c45a1e8c..91184d2739 100644 --- a/README.markdown +++ b/README.markdown @@ -1260,6 +1260,15 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ngx.var.args = nil +**WARNING** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, + + + local val = ngx.var.some_var + --- use the val repeatedly later + + +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** @@ -2791,7 +2800,7 @@ Number literals can be used directly as the argument, for instance, Note that while this method accepts all [HTTP status constants](http://wiki.nginx.org/HttpLuaModule#HTTP_status_constants) as input, it only accepts `NGX_OK` and `NGX_ERROR` of the [core constants](http://wiki.nginx.org/HttpLuaModule#core_constants). -It is strongly recommended to combine the `return` statement with this call, i.e., `return ngx.exit(...)`. +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 ------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f24b01fed6..d429880a08 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1212,6 +1212,15 @@ Setting ngx.var.Foo to a nil value will unset the +'''WARNING''' When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, + + + local val = ngx.var.some_var + --- use the val repeatedly later + + +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*'' @@ -2705,7 +2714,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 strongly recommended to combine the return statement with this call, i.e., return ngx.exit(...). +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()'' From 7ee528b2037dcf807ddbf4b36745bff1104dbd18 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 10 Oct 2012 17:26:54 -0700 Subject: [PATCH 0135/2239] docs: documented the new ngx.thread API. also fixed the __newindex metamethod definition for catching writes to undeclared global varaibles in a Lua module. --- README | 279 ++++++++++++++++++++++++++++++++++++++++- README.markdown | 237 +++++++++++++++++++++++++++++++++- doc/HttpLuaModule.wiki | 235 +++++++++++++++++++++++++++++++++- 3 files changed, 739 insertions(+), 12 deletions(-) diff --git a/README b/README index fc103c3a9f..95de91c20a 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.6.10 - () released on 5 + This document describes ngx_lua v0.7.0 + () released on 10 October 2012. Synopsis @@ -4700,6 +4700,278 @@ Nginx API for Lua 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** + + 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". + + "Light threads" are just a special kind of Lua coroutines that are + scheduled automatically by the "ngx_lua" module. + + Before "ngx.thread.spawn" returns, the "func" will be called with those + optional arguments until it returns, aborts with an error, or gets + yielded automatically due to I/O operations via the Nginx API for Lua + (like ). + + After "ngx.thread.spawn" returns, the newly-created "light thread" will + keep running asynchronously usually at various I/O events. + + All the Lua code chunks running by rewrite_by_lua, access_by_lua, and + content_by_lua are in a boilerplate "light thread" created automatically + by "ngx_lua". Such boilerplate "light thread" are also called "entry + threads". + + By default, the corresponding Nginx handler (e.g., rewrite_by_lua + handler) will not terminate until + + 1. both the "entry thread" and all the user "light threads" terminates, + + 2. a "light thread" (either the "entry thread" or a user "light thread" + aborts by calling ngx.exit, ngx.exec, ngx.redirect, or + ngx.req.set_uri(uri, true), or + + 3. the "entry thread" terminates with a Lua error. + + When the user "light thread" terminates with a Lua error, however, it + will not abort other running "light threads" like the "entry thread" + does. + + Due to the limitation in the Nginx subrequest model, it is not allowed + to abort a running Nginx subrequest in general. So it is also prohibited + to abort a running "light thread" that is pending on one ore more Nginx + subrequests. You must call ngx.thread.wait to wait for those "light + thread" to terminate before quitting the "world". + + The "light threads" are not scheduled in a pre-emptive way. In other + words, no automatic time-slicing is performed. A "light thread" will + keep running exclusively on the CPU until + + 1. a (nonblocking) I/O operation cannot be completed in a single run, + + 2. it calls coroutine.yield to actively give up execution, or + + 3. it is aborted by a Lua error or an invocation of ngx.exit, ngx.exec, + ngx.redirect, or ngx.req.set_uri(uri, true). + + For the first two cases, the "light thread" will usually be resumed + later by the "ngx_lua" scheduler unless a "stop-the-world" event + happens. + + User "light threads" can create "light threads" themselves and normal + user coroutiens created by coroutine.create can also create "light + threads". The coroutine (be it a normal Lua coroutine or a "light + thread") that directly spawns the "light thread" is called the "parent + coroutine" for the "light thread" newly spawned. + + The "parent coroutine" can call ngx.thread.wait to wait on the + termination of its child "light thread". + + You can call coroutine.status() and coroutine.yield() on the "light + thread" coroutines. + + The status of the "light thread" coroutine can be "zombie" if + + 1. the current "light thread" already terminates (either successfully + or with an error), + + 2. its parent coroutine is still alive, and + + 3. its parent coroutine is not waiting on it with ngx.thread.wait. + + The following example demonstrates the use of coroutine.yield() in the + "light thread" coroutines to do manual time-slicing: + + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + + ngx.say("1") + ngx.thread.spawn(f) + + ngx.say("2") + yield(self) + + ngx.say("3") + yield(self) + + ngx.say("4") + + Then it will generate the output + + 0 + 1 + f 1 + 2 + f 2 + 3 + f 3 + 4 + + "Light threads" are mostly useful for doing concurrent upstream requests + in a single Nginx request handler, kinda like a generalized version of + ngx.location.capture_multi that can work with all the Nginx API for Lua. + The following example demonstrates parallel requests to MySQL, + Memcached, and upstream HTTP services in a single Lua handler, and + outputting the results in the order that they actually return (very much + like the Facebook BigPipe model): + + -- query mysql, memcached, and a remote http service at the same time, + -- output the results in the order that they + -- actually return the results. + + local mysql = require "resty.mysql" + local memcached = require "resty.memcached" + + local function query_mysql() + local db = mysql:new() + db:connect{ + host = "127.0.0.1", + port = 3306, + database = "test", + user = "monty", + password = "mypass" + } + local res, err, errno, sqlstate = + db:query("select * from cats order by id asc") + db:set_keepalive(0, 100) + ngx.say("mysql done: ", cjson.encode(res)) + end + + local function query_memcached() + local memc = memcached:new() + memc:connect("127.0.0.1", 11211) + local res, err = memc:get("some_key") + ngx.say("memcached done: ", res) + end + + local function query_http() + local res = ngx.location.capture("/my-http-proxy") + ngx.say("http done: ", res.body) + end + + ngx.thread.spawn(query_mysql) -- create thread 1 + ngx.thread.spawn(query_memcached) -- create thread 2 + ngx.thread.spawn(query_http) -- create thread 3 + + 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** + + 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). + + The arguments "thread1", "thread2", and etc are the Lua thread objects + returned by earlier calls of ngx.thread.spawn. + + The return values have exactly the same meaning as coroutine.resume, + that is, the first value returned is a boolean value indicating whether + the "light thread" terminates successfully or not, and subsequent values + returned are the return values of the user Lua function that was used to + spawn the "light thread" (in case of success) or the error object (in + case of failure). + + Only the direct "parent coroutine" can wait on its child "light thread", + otherwise a Lua exception will be raised. + + The following example demonstrates the use of "ngx.thread.wait" and + ngx.location.capture to emulate ngx.location.capture_multi: + + local capture = ngx.location.capture + local spawn = ngx.thread.spawn + local wait = ngx.thread.wait + local say = ngx.say + + local function fetch(uri) + return capture(uri) + end + + local threads = { + spawn(fetch, "/foo"), + spawn(fetch, "/bar"), + spawn(fetch, "/baz") + } + + for i = 1, #threads do + local ok, res = wait(threads[i]) + if not ok then + say(i, ": failed to run: ", res) + else + say(i, ": status: ", res.status) + say(i, ": body: ", res.body) + end + end + + Here it essentially implements the "wait all" model. + + And below is an example demonstrating the "wait any" model: + + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "f done" + end + + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end + + ngx.say("res: ", res) + + -- stop the "world", aborting other running threads + ngx.exit(ngx.OK) + + And it will generate the following output: + + f thread created: running + g thread created: running + g: hello + res: g done + + This API was first enabled in the "v0.7.0" release. + ndk.set_var.DIRECTIVE syntax: *res = ndk.set_var.DIRECTIVE_NAME* @@ -4943,8 +5215,7 @@ Known Issues module-level global variables that are shared among *all* requests: getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '": ' - .. debug.traceback()) + error('Attempt to write to undeclared variable "' .. key .. '"') end Assuming the current Lua module is named "foo.bar", this will guarantee diff --git a/README.markdown b/README.markdown index 91184d2739..ee8a91baa1 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.6.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 5 October 2012. +This document describes ngx_lua [v0.7.0](https://github.com/chaoslawful/lua-nginx-module/tags) released on 10 October 2012. Synopsis ======== @@ -4207,6 +4207,236 @@ Identical to the standard Lua [coroutine.status](http://www.lua.org/manual/5.1/m 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** + +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". + +"Light threads" are just a special kind of Lua coroutines that are scheduled automatically by the `ngx_lua` module. + +Before `ngx.thread.spawn` returns, the `func` will be called with those optional arguments until it returns, aborts with an error, or gets yielded automatically due to I/O operations via the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) (like [tcpsock:receive](http://wiki.nginx.org/HttpLuaModule#tcpsock:receive)). + +After `ngx.thread.spawn` returns, the newly-created "light thread" will keep running asynchronously usually at various I/O events. + +All the Lua code chunks running by [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua), [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua), and [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) are in a boilerplate "light thread" created automatically by `ngx_lua`. Such boilerplate "light thread" are also called "entry threads". + +By default, the corresponding Nginx handler (e.g., [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) handler) will not terminate until +1. both the "entry thread" and all the user "light threads" terminates, +1. a "light thread" (either the "entry thread" or a user "light thread" aborts by calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), or [ngx.req.set_uri(uri, true)](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_uri), or +1. the "entry thread" terminates with a Lua error. + +When the user "light thread" terminates with a Lua error, however, it will not abort other running "light threads" like the "entry thread" does. + +Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [ngx.thread.wait](http://wiki.nginx.org/HttpLuaModule#ngx.thread.wait) to wait for those "light thread" to terminate before quitting the "world". + +The "light threads" are not scheduled in a pre-emptive way. In other words, no automatic time-slicing is performed. A "light thread" will keep running exclusively on the CPU until +1. a (nonblocking) I/O operation cannot be completed in a single run, +1. it calls [coroutine.yield](http://wiki.nginx.org/HttpLuaModule#coroutine.yield) to actively give up execution, or +1. it is aborted by a Lua error or an invocation of [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), or [ngx.req.set_uri(uri, true)](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_uri). + +For the first two cases, the "light thread" will usually be resumed later by the `ngx_lua` scheduler unless a "stop-the-world" event happens. + +User "light threads" can create "light threads" themselves and normal user coroutiens created by [coroutine.create](http://wiki.nginx.org/HttpLuaModule#coroutine.create) can also create "light threads". The coroutine (be it a normal Lua coroutine or a "light thread") that directly spawns the "light thread" is called the "parent coroutine" for the "light thread" newly spawned. + +The "parent coroutine" can call [ngx.thread.wait](http://wiki.nginx.org/HttpLuaModule#ngx.thread.wait) to wait on the termination of its child "light thread". + +You can call coroutine.status() and coroutine.yield() on the "light thread" coroutines. + +The status of the "light thread" coroutine can be "zombie" if +1. the current "light thread" already terminates (either successfully or with an error), +1. its parent coroutine is still alive, and +1. its parent coroutine is not waiting on it with [ngx.thread.wait](http://wiki.nginx.org/HttpLuaModule#ngx.thread.wait). + +The following example demonstrates the use of coroutine.yield() in the "light thread" coroutines +to do manual time-slicing: + + + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + + ngx.say("1") + ngx.thread.spawn(f) + + ngx.say("2") + yield(self) + + ngx.say("3") + yield(self) + + ngx.say("4") + + +Then it will generate the output + + + 0 + 1 + f 1 + 2 + f 2 + 3 + f 3 + 4 + + +"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) that can work with all the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua). The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): + + + -- query mysql, memcached, and a remote http service at the same time, + -- output the results in the order that they + -- actually return the results. + + local mysql = require "resty.mysql" + local memcached = require "resty.memcached" + + local function query_mysql() + local db = mysql:new() + db:connect{ + host = "127.0.0.1", + port = 3306, + database = "test", + user = "monty", + password = "mypass" + } + local res, err, errno, sqlstate = + db:query("select * from cats order by id asc") + db:set_keepalive(0, 100) + ngx.say("mysql done: ", cjson.encode(res)) + end + + local function query_memcached() + local memc = memcached:new() + memc:connect("127.0.0.1", 11211) + local res, err = memc:get("some_key") + ngx.say("memcached done: ", res) + end + + local function query_http() + local res = ngx.location.capture("/my-http-proxy") + ngx.say("http done: ", res.body) + end + + ngx.thread.spawn(query_mysql) -- create thread 1 + ngx.thread.spawn(query_memcached) -- create thread 2 + ngx.thread.spawn(query_http) -- create thread 3 + + +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** + +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). + +The arguments `thread1`, `thread2`, and etc are the Lua thread objects returned by earlier calls of [ngx.thread.spawn](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn). + +The return values have exactly the same meaning as [coroutine.resume](http://wiki.nginx.org/HttpLuaModule#coroutine.resume), that is, the first value returned is a boolean value indicating whether the "light thread" terminates successfully or not, and subsequent values returned are the return values of the user Lua function that was used to spawn the "light thread" (in case of success) or the error object (in case of failure). + +Only the direct "parent coroutine" can wait on its child "light thread", otherwise a Lua exception will be raised. + +The following example demonstrates the use of `ngx.thread.wait` and [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) to emulate [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi): + + + local capture = ngx.location.capture + local spawn = ngx.thread.spawn + local wait = ngx.thread.wait + local say = ngx.say + + local function fetch(uri) + return capture(uri) + end + + local threads = { + spawn(fetch, "/foo"), + spawn(fetch, "/bar"), + spawn(fetch, "/baz") + } + + for i = 1, #threads do + local ok, res = wait(threads[i]) + if not ok then + say(i, ": failed to run: ", res) + else + say(i, ": status: ", res.status) + say(i, ": body: ", res.body) + end + end + + +Here it essentially implements the "wait all" model. + +And below is an example demonstrating the "wait any" model: + + + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "f done" + end + + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end + + ngx.say("res: ", res) + + -- stop the "world", aborting other running threads + ngx.exit(ngx.OK) + + +And it will generate the following output: + + + f thread created: running + g thread created: running + g: hello + res: g done + + +This API was first enabled in the `v0.7.0` release. + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* @@ -4392,12 +4622,11 @@ It is recommended to always place the following piece of code at the end of Lua getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '": ' - .. debug.traceback()) + error('Attempt to write to undeclared variable "' .. key .. '"') end -Assuming the current Lua module is named `foo.bar`, this will guarantee that local variables in module `foo.bar` functions have been declared as "local". 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. +Assuming the current Lua module is named `foo.bar`, this will guarantee that local variables in module `foo.bar` functions have been declared as `local`. 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 d429880a08..b7b75dc501 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.6.10] released on 5 October 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.0] released on 10 October 2012. = Synopsis = @@ -4060,6 +4060,234 @@ Identical to the standard Lua [http://www.lua.org/manual/5.1/manual.html#pdf-cor 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*'' + +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". + +"Light threads" are just a special kind of Lua coroutines that are scheduled automatically by the ngx_lua module. + +Before ngx.thread.spawn returns, the func will be called with those optional arguments until it returns, aborts with an error, or gets yielded automatically due to I/O operations via the [[#Nginx API for Lua|Nginx API for Lua]] (like [[#tcpsock:receive|tcpsock:receive]]). + +After ngx.thread.spawn returns, the newly-created "light thread" will keep running asynchronously usually at various I/O events. + +All the Lua code chunks running by [[#rewrite_by_lua|rewrite_by_lua]], [[#access_by_lua|access_by_lua]], and [[#content_by_lua|content_by_lua]] are in a boilerplate "light thread" created automatically by ngx_lua. Such boilerplate "light thread" are also called "entry threads". + +By default, the corresponding Nginx handler (e.g., [[#rewrite_by_lua|rewrite_by_lua]] handler) will not terminate until +# both the "entry thread" and all the user "light threads" terminates, +# a "light thread" (either the "entry thread" or a user "light thread" aborts by calling [[#ngx.exit|ngx.exit]], [[#ngx.exec|ngx.exec]], [[#ngx.redirect|ngx.redirect]], or [[#ngx.req.set_uri|ngx.req.set_uri(uri, true)]], or +# the "entry thread" terminates with a Lua error. + +When the user "light thread" terminates with a Lua error, however, it will not abort other running "light threads" like the "entry thread" does. + +Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [[#ngx.thread.wait|ngx.thread.wait]] to wait for those "light thread" to terminate before quitting the "world". + +The "light threads" are not scheduled in a pre-emptive way. In other words, no automatic time-slicing is performed. A "light thread" will keep running exclusively on the CPU until +# a (nonblocking) I/O operation cannot be completed in a single run, +# it calls [[#coroutine.yield|coroutine.yield]] to actively give up execution, or +# it is aborted by a Lua error or an invocation of [[#ngx.exit|ngx.exit]], [[#ngx.exec|ngx.exec]], [[#ngx.redirect|ngx.redirect]], or [[#ngx.req.set_uri|ngx.req.set_uri(uri, true)]]. + +For the first two cases, the "light thread" will usually be resumed later by the ngx_lua scheduler unless a "stop-the-world" event happens. + +User "light threads" can create "light threads" themselves and normal user coroutiens created by [[#coroutine.create|coroutine.create]] can also create "light threads". The coroutine (be it a normal Lua coroutine or a "light thread") that directly spawns the "light thread" is called the "parent coroutine" for the "light thread" newly spawned. + +The "parent coroutine" can call [[#ngx.thread.wait|ngx.thread.wait]] to wait on the termination of its child "light thread". + +You can call coroutine.status() and coroutine.yield() on the "light thread" coroutines. + +The status of the "light thread" coroutine can be "zombie" if +# the current "light thread" already terminates (either successfully or with an error), +# its parent coroutine is still alive, and +# its parent coroutine is not waiting on it with [[#ngx.thread.wait|ngx.thread.wait]]. + +The following example demonstrates the use of coroutine.yield() in the "light thread" coroutines +to do manual time-slicing: + + + local yield = coroutine.yield + + function f() + local self = coroutine.running() + ngx.say("f 1") + yield(self) + ngx.say("f 2") + yield(self) + ngx.say("f 3") + end + + local self = coroutine.running() + ngx.say("0") + yield(self) + + ngx.say("1") + ngx.thread.spawn(f) + + ngx.say("2") + yield(self) + + ngx.say("3") + yield(self) + + ngx.say("4") + + +Then it will generate the output + + + 0 + 1 + f 1 + 2 + f 2 + 3 + f 3 + 4 + + +"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [[#ngx.location.capture_multi|ngx.location.capture_multi]] that can work with all the [[#Nginx API for Lua|Nginx API for Lua]]. The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): + + + -- query mysql, memcached, and a remote http service at the same time, + -- output the results in the order that they + -- actually return the results. + + local mysql = require "resty.mysql" + local memcached = require "resty.memcached" + + local function query_mysql() + local db = mysql:new() + db:connect{ + host = "127.0.0.1", + port = 3306, + database = "test", + user = "monty", + password = "mypass" + } + local res, err, errno, sqlstate = + db:query("select * from cats order by id asc") + db:set_keepalive(0, 100) + ngx.say("mysql done: ", cjson.encode(res)) + end + + local function query_memcached() + local memc = memcached:new() + memc:connect("127.0.0.1", 11211) + local res, err = memc:get("some_key") + ngx.say("memcached done: ", res) + end + + local function query_http() + local res = ngx.location.capture("/my-http-proxy") + ngx.say("http done: ", res.body) + end + + ngx.thread.spawn(query_mysql) -- create thread 1 + ngx.thread.spawn(query_memcached) -- create thread 2 + ngx.thread.spawn(query_http) -- create thread 3 + + +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*'' + +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). + +The arguments thread1, thread2, and etc are the Lua thread objects returned by earlier calls of [[#ngx.thread.spawn|ngx.thread.spawn]]. + +The return values have exactly the same meaning as [[#coroutine.resume|coroutine.resume]], that is, the first value returned is a boolean value indicating whether the "light thread" terminates successfully or not, and subsequent values returned are the return values of the user Lua function that was used to spawn the "light thread" (in case of success) or the error object (in case of failure). + +Only the direct "parent coroutine" can wait on its child "light thread", otherwise a Lua exception will be raised. + +The following example demonstrates the use of ngx.thread.wait and [[#ngx.location.capture|ngx.location.capture]] to emulate [[#ngx.location.capture_multi|ngx.location.capture_multi]]: + + + local capture = ngx.location.capture + local spawn = ngx.thread.spawn + local wait = ngx.thread.wait + local say = ngx.say + + local function fetch(uri) + return capture(uri) + end + + local threads = { + spawn(fetch, "/foo"), + spawn(fetch, "/bar"), + spawn(fetch, "/baz") + } + + for i = 1, #threads do + local ok, res = wait(threads[i]) + if not ok then + say(i, ": failed to run: ", res) + else + say(i, ": status: ", res.status) + say(i, ": body: ", res.body) + end + end + + +Here it essentially implements the "wait all" model. + +And below is an example demonstrating the "wait any" model: + + + function f() + ngx.sleep(0.2) + ngx.say("f: hello") + return "f done" + end + + function g() + ngx.sleep(0.1) + ngx.say("g: hello") + return "g done" + end + + local tf, err = ngx.thread.spawn(f) + if not tf then + ngx.say("failed to spawn thread f: ", err) + return + end + + ngx.say("f thread created: ", coroutine.status(tf)) + + local tg, err = ngx.thread.spawn(g) + if not tg then + ngx.say("failed to spawn thread g: ", err) + return + end + + ngx.say("g thread created: ", coroutine.status(tg)) + + ok, res = ngx.thread.wait(tf, tg) + if not ok then + ngx.say("failed to wait: ", res) + return + end + + ngx.say("res: ", res) + + -- stop the "world", aborting other running threads + ngx.exit(ngx.OK) + + +And it will generate the following output: + + + f thread created: running + g thread created: running + g: hello + res: g done + + +This API was first enabled in the v0.7.0 release. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' @@ -4237,12 +4465,11 @@ It is recommended to always place the following piece of code at the end of Lua getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '": ' - .. debug.traceback()) + error('Attempt to write to undeclared variable "' .. key .. '"') end -Assuming the current Lua module is named foo.bar, this will guarantee that local variables in module foo.bar functions have been declared as "local". 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. +Assuming the current Lua module is named foo.bar, this will guarantee that local variables in module foo.bar functions have been declared as local. 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 3875a33976dc295d9d4f198029847a80fc57817d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 12 Oct 2012 19:39:15 -0700 Subject: [PATCH 0136/2239] bugfix: ngx.re.gsub() might throw out the "attempt to call a string value" exception when the "replace" argument is a Lua function and the subject string is large. thanks Zhu Maohai for reporting this issue. --- src/ngx_http_lua_regex.c | 6 ++- t/037-gsub.t | 110 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 494d6649d7..1ee9189417 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1492,7 +1492,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } if (func) { - lua_pushvalue(L, -1); + lua_pushvalue(L, 3); lua_createtable(L, rc - 1 /* narr */, 1 /* nrec */); @@ -1529,12 +1529,14 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) return luaL_argerror(L, 3, msg); } + lua_insert(L, 1); + luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], cap[0] - cp_offset); luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); - lua_pop(L, 1); + lua_remove(L, 1); cp_offset = cap[1]; offset = cp_offset; diff --git a/t/037-gsub.t b/t/037-gsub.t index cbc6ab2101..68d88e255d 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 + 4); +plan tests => repeat_each() * (blocks() * 2 + 8); #no_diff(); no_long_string(); @@ -255,3 +255,111 @@ n: 1 --- no_error_log [error] + + +=== TEST 14: big subject string exceeding the luabuf chunk size (with trailing unmatched data, func repl) +--- config + location /re { + content_by_lua ' + local subj = string.rep("a", 8000) + .. string.rep("b", 1000) + .. string.rep("a", 8000) + .. string.rep("b", 1000) + .. "aaa" + + local function repl(m) + return string.rep("c", string.len(m[0])) + end + + local s, n = ngx.re.gsub(subj, "b+", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body eval +("a" x 8000) . ("c" x 1000) . ("a" x 8000) . ("c" x 1000) +. "aaa +2 +" +--- no_error_log +[error] + + + +=== TEST 15: big subject string exceeding the luabuf chunk size (without trailing unmatched data, func repl) +--- config + location /re { + content_by_lua ' + local subj = string.rep("a", 8000) + .. string.rep("b", 1000) + .. string.rep("a", 8000) + .. string.rep("b", 1000) + + local function repl(m) + return string.rep("c", string.len(m[0])) + end + + local s, n = ngx.re.gsub(subj, "b+", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body eval +("a" x 8000) . ("c" x 1000) . ("a" x 8000) . ("c" x 1000) +. "\n2\n" +--- no_error_log +[error] + + + +=== TEST 16: big subject string exceeding the luabuf chunk size (with trailing unmatched data, str repl) +--- config + location /re { + content_by_lua ' + local subj = string.rep("a", 8000) + .. string.rep("b", 1000) + .. string.rep("a", 8000) + .. string.rep("b", 1000) + .. "aaa" + + local s, n = ngx.re.gsub(subj, "b(b+)(b)", "$1 $2") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body eval +("a" x 8000) . ("b" x 998) . " b" . ("a" x 8000) . ("b" x 998) . " baaa +2 +" +--- no_error_log +[error] + + + +=== TEST 17: big subject string exceeding the luabuf chunk size (without trailing unmatched data, str repl) +--- config + location /re { + content_by_lua ' + local subj = string.rep("a", 8000) + .. string.rep("b", 1000) + .. string.rep("a", 8000) + .. string.rep("b", 1000) + + local s, n = ngx.re.gsub(subj, "b(b+)(b)", "$1 $2") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body eval +("a" x 8000) . ("b" x 998) . " b" . ("a" x 8000) . ("b" x 998) . " b\n2\n" +--- no_error_log +[error] + From db2d5310b3c266734dbe04479e77361cfa75e4bd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 13 Oct 2012 20:02:59 -0700 Subject: [PATCH 0137/2239] docs: massive wording improvements from Dayo. also bumped version to 0.7.1. --- README | 303 ++++++++++++++++++++--------------------- README.markdown | 145 ++++++++++---------- doc/HttpLuaModule.wiki | 145 ++++++++++---------- 3 files changed, 284 insertions(+), 309 deletions(-) diff --git a/README b/README index 95de91c20a..ff4959e917 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.0 - () released on 10 + This document describes ngx_lua v0.7.1 + () released on 13 October 2012. Synopsis @@ -257,9 +257,9 @@ Directives to to reload the config file are to send a "HUP" signal or to restart Nginx. - 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. + 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. Disabling the Lua code cache is strongly discouraged for production use and should only be used during development as it has a significant @@ -628,7 +628,7 @@ Directives fastcgi_pass ...; } - can be implemented in "ngx_lua" as: + can be implemented in ngx_lua as: location = /check-spam { internal; @@ -751,7 +751,7 @@ Directives # proxy_pass/fastcgi_pass/postgres_pass/... } - can be implemented in "ngx_lua" as: + can be implemented in ngx_lua as: location / { access_by_lua ' @@ -1073,8 +1073,8 @@ Directives client_body_buffer_size must have the same value as client_max_body_size. Because when the content length exceeds client_body_buffer_size but less than client_max_body_size, Nginx will - automatically buffer the data into a temporary file on the disk, which - will lead to empty value in the $request_body variable. + buffer the data into a temporary file on the disk, which will lead to + empty value in the $request_body variable. If the current location includes rewrite_by_lua or rewrite_by_lua_file directives, then the request body will be read just before the @@ -1205,9 +1205,9 @@ Directives Default to 30 connections for every pool. - When the connection pool is exceeding the size limit, the least recently - used (idle) connection already in the pool will be closed automatically - to make room for the current connection. + 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 @@ -1224,8 +1224,8 @@ Directives This directive controls the default maximal idle time of the connections in the cosocket built-in connection pool. When this timeout reaches, - idle connections will be closed automatically and removed from the pool. - This setting can be overridden by cosocket objects' setkeepalive method. + idle connections will be closed and removed from the pool. This setting + can be overridden by cosocket objects' setkeepalive method. The " -where in the latter case, this method will automatically escape argument keys and values according to the URI escaping rule. +where in the latter case, this method will escape argument keys and values according to the URI escaping rule. Multi-value arguments are also supported: @@ -2020,7 +2020,7 @@ Then GET /test?foo=bar&bar=baz&bar=blah will yield the response bod Multiple occurrences of an argument key will result in a table value holding all the values for that key in order. -Keys and values are automatically unescaped according to URI escaping rules. In the settings above, GET /test?a%20b=1%61+2 will yield: +Keys and values are unescaped according to URI escaping rules. In the settings above, GET /test?a%20b=1%61+2 will yield: a b: 1a 2 @@ -2112,7 +2112,7 @@ will yield the response body like Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order. -Keys and values will be automatically unescaped according to URI escaping rules. +Keys and values will be unescaped according to URI escaping rules. With the settings above, @@ -2213,7 +2213,7 @@ Removing the max_headers cap is strongly discouraged. Since the 0.6.9 release, all the header names in the Lua table returned are converted to the pure lower-case form by default, unless the raw argument is set to true (default to false). -Also, by default, an __index metamethod is added automatically to the resulting Lua table that will normalize the keys to the pure lower-case form with all underscores converted to dashes in case of a lookup miss. For example, if a request header My-Foo-Header is present, then the following invocations will all pick up the value of this header correctly: +Also, by default, an __index metamethod is added to the resulting Lua table and will normalize the keys to a pure lowercase form with all underscores converted to dashes in case of a lookup miss. For example, if a request header My-Foo-Header is present, then the following invocations will all pick up the value of this header correctly: ngx.say(headers.my_foo_header) @@ -2230,7 +2230,7 @@ The __index metamethod will not be added when the raw Set the current request's request header named header_name to value header_value, overriding any existing ones. -By default, all the subrequests subsequently initiated by [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] will automatically inherit the new header. +By default, all the subrequests subsequently initiated by [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] will inherit the new header. Here is an example of setting the Content-Length header: @@ -2320,7 +2320,7 @@ This function returns nil if # the request body has been read into disk temporary files, # or the request body has zero size. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body automatically, but this is not recommended). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead. @@ -2339,9 +2339,9 @@ See also [[#ngx.req.get_body_file|ngx.req.get_body_file]]. Retrieves the file name for the in-file request body data. Returns nil if the request body has not been read or has been read into memory. -The returned file is read only and is usually cleaned up automatically by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. +The returned file is read only and is usually cleaned up by Nginx's memory pool. It should not be manually modified, renamed, or removed in Lua code. -If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body automatically, but this is not recommended). +If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body. This is not recommended however). If the request body has been read into memory, try calling the [[#ngx.req.get_body_data|ngx.req.get_body_data]] function instead. @@ -2375,7 +2375,7 @@ See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. Set the current request's request body using the in-file data specified by the file_name argument. -If the optional auto_clean argument is given a true value, then this file will be automatically removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. +If the optional auto_clean argument is given a true value, then this file will be removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The auto_clean is default to false. Please ensure that the file specified by the file_name argument exists and is readable by an Nginx worker process by setting its permission properly to avoid Lua exception errors. @@ -2397,7 +2397,7 @@ Creates a new blank request body for the current request and inializes the buffe If the buffer_size argument is specified, then its value will be used for the size of the memory buffer for body writing with [[#ngx.req.append_body|ngx.req.append_body]]. If the argument is omitted, then the value specified by the standard [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] directive will be used instead. -When the data can no longer be hold in the memory buffer for the request body, then the data will automatically be flushed onto a temporary file just like the standard request body reader in the Nginx core. +When the data can no longer be hold in the memory buffer for the request body, then the data will be flushed onto a temporary file just like the standard request body reader in the Nginx core. It is important to always call the [[#ngx.req.finish_body|ngx.req.finish_body]] after all the data has been appended onto the current request body. Also, when this function is used together with [[#ngx.req.socket|ngx.req.socket]], it is required to call [[#ngx.req.socket|ngx.req.socket]] ''before'' this function, or you will get the "request body already exists" error message. @@ -2422,7 +2422,7 @@ This function was first introduced in the v0.5.11 release. Append new data chunk specified by the data_chunk argument onto the existing request body created by the [[#ngx.req.init_body|ngx.req.init_body]] call. -When the data can no longer be hold in the memory buffer for the request body, then the data will automatically be flushed onto a temporary file just like the standard request body reader in the Nginx core. +When the data can no longer be hold in the memory buffer for the request body, then the data will be flushed onto a temporary file just like the standard request body reader in the Nginx core. It is important to always call the [[#ngx.req.finish_body|ngx.req.finish_body]] after all the data has been appended onto the current request body. @@ -2456,7 +2456,7 @@ 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 there is any request body data that has been pre-read into the Nginx core's request header buffer, the resulting cosocket object will take care of that automatically. So there will not be any data loss due to potential body data pre-reading. +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. This function was first introduced in the v0.5.0rc1 release. @@ -2500,7 +2500,7 @@ The optional second args can be used to specify extra URI query arg ngx.exec("/foo", "a=3&b=hello%20world") -Alternatively, a Lua table can be passed for the args argument for ngx_lua to carry out URI escaping and string concatenation automatically. +Alternatively, a Lua table can be passed for the args argument for ngx_lua to carry out URI escaping and string concatenation. ngx.exec("/foo", { a = 3, b = "hello world" }) @@ -2592,7 +2592,7 @@ It is strongly recommended to combine the return statement with thi Explicitly send out the response headers. -Note that there is normally no need to manually send out response headers as ngx_lua will automatically send headers out +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. == ngx.headers_sent == @@ -2600,9 +2600,9 @@ before content is output with [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] o '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Returns true if the response headers have been sent (by ngx_lua), and false otherwise. +Returns true if the response headers have been sent (by ngx_lua), and false otherwise. -This API was first introduced in ngx_lua v0.3.1rc6. +This API was first introduced in ngx_lua v0.3.1rc6. == ngx.print == '''syntax:''' ''ngx.print(...)'' @@ -3066,7 +3066,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. +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. @@ -3205,7 +3205,7 @@ This feature was first introduced in the v0.2.1rc12 release. '''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]]. +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). @@ -3577,7 +3577,7 @@ Sends data on the current UDP or datagram unix domain socket object. In case of success, it returns 1. Otherwise, it returns nil and a string describing the error. -The input argument data can either be a Lua string or a (nested) Lua table holding string fragments. In case of table arguments, this method will automatically copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land. +The input argument data can either be a Lua string or a (nested) Lua table holding string fragments. In case of table arguments, this method will copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land. This feature was first introduced in the v0.5.7 release. @@ -3619,7 +3619,7 @@ This feature was first introduced in the v0.5.7 release. 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. -For socket objects that have not invoked this method, they (and their connections) will be automatically closed when the socket object is released by the Lua GC (Garbage Collector) or the current client HTTP request finishes processing. +Socket objects that have not invoked this method (and associated connections) will be closed when the socket object is released by the Lua GC (Garbage Collector) or the current client HTTP request finishes processing. This feature was first introduced in the v0.5.7 release. @@ -3725,7 +3725,7 @@ Calling this method on an already connected socket object will cause the origina An optional Lua table can be specified as the last argument to this method to specify various connect options: * pool -: specify a custom name for the connection pool being used. If omitted, then the connection pool name will be automatically generated from the string template ":" or "". +: specify a custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template ":" or "". The support for the options table argument was first introduced in the v0.5.7 release. @@ -3742,7 +3742,7 @@ This method is a synchronous operation that will not return until ''all'' the da In case of success, it returns the total number of bytes that have been sent. Otherwise, it returns nil and a string describing the error. -The input argument data can either be a Lua string or a (nested) Lua table holding string fragments. In case of table arguments, this method will automatically copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land. +The input argument data can either be a Lua string or a (nested) Lua table holding string fragments. In case of table arguments, this method will copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land. Timeout for the sending operation is controlled by the [[#lua_socket_send_timeout|lua_socket_send_timeout]] config directive and the [[#tcpsock:settimeout|settimeout]] method. And the latter takes priority. For example: @@ -3817,7 +3817,7 @@ In case of error, the iterator function will return nil along with The iterator function can be called multiple times and can be mixed safely with other cosocket method calls or other iterator function calls. -The iterator function behaves differently (i.e., like a real iterator) when it is called with a size argument. That is, it will read that size of data on each invocation and will return nil at the last invocation (either sees the boundary pattern or meets an error). For the last successful invocation of the iterator function, the err return value will be nil too. The iterator function will automatically reset after its last successful invocation that returns nil data and nil error. Consider the following example: +The iterator function behaves differently (i.e., like a real iterator) when it is called with a size argument. That is, it will read that size of data on each invocation and will return nil at the last invocation (either sees the boundary pattern or meets an error). For the last successful invocation of the iterator function, the err return value will be nil too. The iterator function will be reset after the last successful invocation that returns nil data and nil error. Consider the following example: local reader = sock:receiveuntil("\r\n--abcedhb") @@ -3890,9 +3890,9 @@ This method was first introduced in the v0.5.0rc1 release. 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. -For socket objects that have invoked the [[#tcpsock:setkeepalive|setkeepalive]] method, there is no need to call this method on it because the socket object is already closed (and the current connection is saved into the built-in connection pool). +Note that there is no need to call this method on socket objects that have invoked the [[#tcpsock:setkeepalive|setkeepalive]] method because the socket object is already closed (and the current connection is saved into the built-in connection pool). -For socket objects that have not invoked [[#tcpsock:setkeepalive|setkeepalive]] nor this method, they (and their connections) will be automatically closed when the socket object is released by the Lua GC (Garbage Collector) or the current client HTTP request finishes processing. +Socket objects that have not invoked this method (and associated connections) will be closed when the socket object is released by the Lua GC (Garbage Collector) or the current client HTTP request finishes processing. This feature was first introduced in the v0.5.0rc1 release. @@ -3929,7 +3929,7 @@ The first optional argument, timeout, can be used to specify the ma The second optional argument, size, can be used to specify the maximal number of connections allowed in the connection pool for the current server (i.e., the current host-port pair or the unix domain socket file path). Note that the size of the connection pool cannot be changed once the pool is created. When this argument is omitted, the default setting in the [[#lua_socket_pool_size|lua_socket_pool_size]] config directive will be used. -When the connection pool is exceeding the size limit, the least recently used (idle) connection already in the pool will be closed automatically to make room for the current connection. +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 the size limit specified here also applies to every single Nginx worker process. @@ -4007,7 +4007,7 @@ This API was first introduced in the v0.5.10 release. Creates a user Lua coroutines with a Lua function, and returns a coroutine object. -Just behaves like 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 automatically by this Nginx module. +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. @@ -4018,7 +4018,7 @@ This API was first introduced in the v0.6.0 release. Resumes the executation of a user Lua coroutine object previously yielded or just created. -Just behaves like 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 automatically by this Nginx module. +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. @@ -4029,7 +4029,7 @@ This API was first introduced in the v0.6.0 release. Yields the executation of the current user Lua coroutine. -Just behaves like 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 automatically by this Nginx module. +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. @@ -4038,7 +4038,7 @@ This API was first introduced in the v0.6.0 release. '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Just behaves like 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 automatically by this Nginx module. +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. @@ -4067,13 +4067,13 @@ This API was first enabled in the v0.6.0 release. 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". -"Light threads" are just a special kind of Lua coroutines that are scheduled automatically by the ngx_lua module. +"Light threads" are just a special kind of Lua coroutines that are scheduled by the ngx_lua module. -Before ngx.thread.spawn returns, the func will be called with those optional arguments until it returns, aborts with an error, or gets yielded automatically due to I/O operations via the [[#Nginx API for Lua|Nginx API for Lua]] (like [[#tcpsock:receive|tcpsock:receive]]). +Before ngx.thread.spawn returns, the func will be called with those optional arguments until it returns, aborts with an error, or gets yielded due to I/O operations via the [[#Nginx API for Lua|Nginx API for Lua]] (like [[#tcpsock:receive|tcpsock:receive]]). After ngx.thread.spawn returns, the newly-created "light thread" will keep running asynchronously usually at various I/O events. -All the Lua code chunks running by [[#rewrite_by_lua|rewrite_by_lua]], [[#access_by_lua|access_by_lua]], and [[#content_by_lua|content_by_lua]] are in a boilerplate "light thread" created automatically by ngx_lua. Such boilerplate "light thread" are also called "entry threads". +All the Lua code chunks running by [[#rewrite_by_lua|rewrite_by_lua]], [[#access_by_lua|access_by_lua]], and [[#content_by_lua|content_by_lua]] are in a boilerplate "light thread" created automatically by ngx_lua. Such boilerplate "light thread" are also called "entry threads". By default, the corresponding Nginx handler (e.g., [[#rewrite_by_lua|rewrite_by_lua]] handler) will not terminate until # both the "entry thread" and all the user "light threads" terminates, @@ -4084,12 +4084,12 @@ When the user "light thread" terminates with a Lua error, however, it will not a Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [[#ngx.thread.wait|ngx.thread.wait]] to wait for those "light thread" to terminate before quitting the "world". -The "light threads" are not scheduled in a pre-emptive way. In other words, no automatic time-slicing is performed. A "light thread" will keep running exclusively on the CPU until +The "light threads" are not scheduled in a pre-emptive way. In other words, no time-slicing is performed automatically. A "light thread" will keep running exclusively on the CPU until # a (nonblocking) I/O operation cannot be completed in a single run, # it calls [[#coroutine.yield|coroutine.yield]] to actively give up execution, or # it is aborted by a Lua error or an invocation of [[#ngx.exit|ngx.exit]], [[#ngx.exec|ngx.exec]], [[#ngx.redirect|ngx.redirect]], or [[#ngx.req.set_uri|ngx.req.set_uri(uri, true)]]. -For the first two cases, the "light thread" will usually be resumed later by the ngx_lua scheduler unless a "stop-the-world" event happens. +For the first two cases, the "light thread" will usually be resumed later by the ngx_lua scheduler unless a "stop-the-world" event happens. User "light threads" can create "light threads" themselves and normal user coroutiens created by [[#coroutine.create|coroutine.create]] can also create "light threads". The coroutine (be it a normal Lua coroutine or a "light thread") that directly spawns the "light thread" is called the "parent coroutine" for the "light thread" newly spawned. @@ -4329,7 +4329,7 @@ This feature requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] 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. -Please note that the bytecode format used by LuaJIT 2.0 is not compatible with that for the standard Lua 5.1 interpreter. So if using LuaJIT 2.0 with ngx_lua, LuaJIT-compatible bytecode files must be generated as shown: +Please note that the bytecode format used by LuaJIT 2.0 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac @@ -4341,11 +4341,11 @@ The -bg option can be used to include debug information in the LuaJ /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac -Please refer to the official LuaJIT documentation for the -b option for more details: +Please refer to the official LuaJIT documentation on the -b option for more details: http://luajit.org/running.html#opt_b -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua-compatible bytecode files must be generated using the luac command-line utility as shown: +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: luac -o /path/to/output_file.luac /path/to/input_file.lua @@ -4357,7 +4357,7 @@ Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecod luac -s -o /path/to/output_file.luac /path/to/input_file.lua -Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0 or vice versa, an error message such as that below will be logged in the Nginx error.log file: +Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0 or vice versa, will result in an error message, such as that below, being logged into the Nginx error.log file: [error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac @@ -4367,21 +4367,16 @@ Loading bytecode files via the Lua primitives like require and Content-Length header when the response body is non-empty in order to support the HTTP 1.0 keep-alive (as required by the ApacheBench (ab) tool). So when -an HTTP 1.0 request is present and the [[#lua_http10_buffering|lua_http10_buffering]] directive is turned on, this module will automatically buffer all the -outputs of user calls of [[#ngx.say|ngx.say]] and [[#ngx.print|ngx.print]] and -postpone sending response headers until it sees all the outputs in the response -body, and at that time ngx_lua can calculate the total length of the body and -construct a proper Content-Length header for the HTTP 1.0 client. - -If the user Lua code sets the Content-Length response header itself, then the automatic buffering will be disabled even if the [[#lua_http10_buffering|lua_http10_buffering]] directive is turned on. +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|ngx.say]] and [[#ngx.print|ngx.print]] 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. For large streaming output responses, it is important to disable the [[#lua_http10_buffering|lua_http10_buffering]] directive to minimise memory usage. -Note that, common HTTP benchmark tools like ab and http_load always issue -HTTP 1.0 requests by default. To force curl to send HTTP 1.0 requests, use -the -0 option. +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. = Data Sharing within an Nginx Worker = @@ -4420,7 +4415,7 @@ and all subsequent requests to the same nginx worker process will use the reload 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. -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. +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. If server-wide data sharing is required, then use one or more of the following approaches: # Use the [[#ngx.shared.DICT|ngx.shared.DICT]] API provided by this module. @@ -4438,7 +4433,7 @@ 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|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. +* 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. == Lua Variable Scope == @@ -4600,8 +4595,8 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k = Nginx Compatibility = The module is compatible with the following versions of Nginx: -* 1.3.x (last tested: 1.3.6) -* 1.2.x (last tested: 1.2.3) +* 1.3.x (last tested: 1.3.7) +* 1.2.x (last tested: 1.2.4) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) @@ -4613,21 +4608,21 @@ The code repository of this project is hosted on github at [http://github.com/ch = 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, as well as a package of powerful companion Nginx modules. The basic installation step is a simple ./configure --with-luajit && make && make install. +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, 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: +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. # 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/chaoslawful/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.2.3.tar.gz' - tar -xzvf nginx-1.2.3.tar.gz - cd nginx-1.2.3/ + wget 'http://nginx.org/download/nginx-1.2.4.tar.gz' + tar -xzvf nginx-1.2.4.tar.gz + cd nginx-1.2.4/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib @@ -4698,7 +4693,7 @@ Please submit bug reports, wishlists, or patches by == 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 Lua code automatic time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. +* 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]. = Changes = From b5531ff5bec2d82715b6626f0a4d6b8d85dadb0a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 15 Oct 2012 11:34:02 -0700 Subject: [PATCH 0138/2239] feature: now we can automatically detect the vendor-provided LuaJIT-2.0 package on Gentoo. thanks Il'ya V. Yesin for the patch in github pull #167. it is still recommended, however, to explicitly set the environments LUAJIT_INC and LUAJIT_LIB. --- config | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/config b/config index eeb3bf37c4..ae7991efd9 100644 --- a/config +++ b/config @@ -20,7 +20,7 @@ if [ -n "$LUAJIT_INC" -o -n "$LUAJIT_LIB" ]; then if [ $ngx_found = no ]; then cat << END - $0: error: ngx_http_lua_module requires the Lua or LuaJIT library and LUAJIT_LIB is defined as $LUAJIT_LIB and LUAJIT_INC $LUAJIT_INC, but we cannot find LuaJIT there. + $0: error: ngx_http_lua_module requires the Lua or LuaJIT library and LUAJIT_LIB is defined as $LUAJIT_LIB and LUAJIT_INC (path for lua.h) $LUAJIT_INC, but we cannot find LuaJIT there. END exit 1 fi @@ -56,7 +56,7 @@ else if [ $ngx_found = no ]; then cat << END - $0: error: ngx_http_lua_module requires the Lua or LuaJIT library and LUA_LIB is defined as $LUA_LIB and LUA_INC is $LUA_INC, but we cannot find standard Lua there. + $0: error: ngx_http_lua_module requires the Lua or LuaJIT library and LUA_LIB is defined as $LUA_LIB and LUA_INC (path for lua.h) is $LUA_INC, but we cannot find standard Lua there. END exit 1 fi @@ -125,6 +125,18 @@ END fi . auto/feature fi + + if [ $ngx_found = no ]; then + # Gentoo with LuaJIT-2.0 + ngx_feature="LuaJIT library in /usr/" + ngx_feature_path="/usr/include/luajit-2.0" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1" + else + ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1" + fi + . auto/feature + fi fi fi From e607b639beb8a7dfe71eef07654560a32ad6b5a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 17 Oct 2012 15:20:37 -0700 Subject: [PATCH 0139/2239] bumped version to 0.7.2. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index ff4959e917..c750119b7e 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.1 - () released on 13 + This document describes ngx_lua v0.7.2 + () released on 17 October 2012. Synopsis diff --git a/README.markdown b/README.markdown index a9e8b93bbf..6067b3ef6d 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.1](https://github.com/chaoslawful/lua-nginx-module/tags) released on 13 October 2012. +This document describes ngx_lua [v0.7.2](https://github.com/chaoslawful/lua-nginx-module/tags) released on 17 October 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index db45f00565..3ed596d895 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.1] released on 13 October 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.2] released on 17 October 2012. = Synopsis = From f928feae8d3b4de4d5790cab06f27e4ca34698f8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 29 Oct 2012 18:09:31 -0700 Subject: [PATCH 0140/2239] feature: added the "get_keys" method for the shared dictionaries for fetching all the (or the specified number of) keys (default to 1024 keys). thanks Brian Akins for the patch in pull \#170. --- src/ngx_http_lua_shdict.c | 104 +++++++++++++++++++- t/043-shdict.t | 195 ++++++++++++++++++++++++++++++++++++++ t/062-count.t | 2 +- 3 files changed, 299 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 90c99e3d23..4fd0c65c55 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -24,6 +24,7 @@ static int ngx_http_lua_shdict_incr(lua_State *L); static int ngx_http_lua_shdict_delete(lua_State *L); static int ngx_http_lua_shdict_flush_all(lua_State *L); static int ngx_http_lua_shdict_flush_expired(lua_State *L); +static int ngx_http_lua_shdict_get_keys(lua_State *L); #define NGX_HTTP_LUA_SHDICT_ADD 0x0001 @@ -282,7 +283,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 */, 9 /* nrec */); /* shared mt */ + lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* shared mt */ lua_pushcfunction(L, ngx_http_lua_shdict_get); lua_setfield(L, -2, "get"); @@ -308,6 +309,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired); lua_setfield(L, -2, "flush_expired"); + lua_pushcfunction(L, ngx_http_lua_shdict_get_keys); + lua_setfield(L, -2, "get_keys"); + lua_pushvalue(L, -1); /* shared mt mt */ lua_setfield(L, -2, "__index"); /* shared mt */ @@ -617,6 +621,104 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) } +/* + * This trades CPU for memory. This is potentially slow. O(2n) + */ + +static int +ngx_http_lua_shdict_get_keys(lua_State *L) +{ + ngx_queue_t *q, *prev; + ngx_http_lua_shdict_node_t *sd; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + int total = 0; + int attempts = 1024; + uint64_t now; + int n; + + n = lua_gettop(L); + + if (n != 1 && n != 2) { + return luaL_error(L, "expecting 1 or 2 argument(s), " + "but saw %d", n); + } + + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + + zone = lua_touserdata(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); + } + + if (n == 2) { + attempts = luaL_checknumber(L, 2); + } + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + if (ngx_queue_empty(&ctx->sh->queue)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_createtable(L, 0, 0); + return 1; + } + + tp = ngx_timeofday(); + + now = (uint64_t) tp->sec * 1000 + tp->msec; + + /* first run through: get total number of elements we need to allocate */ + + q = ngx_queue_last(&ctx->sh->queue); + + while (q != ngx_queue_sentinel(&ctx->sh->queue)) { + prev = ngx_queue_prev(q); + + sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); + + if (sd->expires == 0 || sd->expires > now) { + total++; + if (attempts && total == attempts) { + break; + } + } + + q = prev; + } + + lua_createtable(L, total, 0); + + /* second run through: add keys to table */ + + total = 0; + q = ngx_queue_last(&ctx->sh->queue); + + while (q != ngx_queue_sentinel(&ctx->sh->queue)) { + prev = ngx_queue_prev(q); + + sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); + + if (sd->expires == 0 || sd->expires > now) { + lua_pushlstring(L, (char *) sd->data, sd->key_len); + lua_rawseti(L, -2, ++total); + if (attempts && total == attempts) { + break; + } + } + + q = prev; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + /* table is at top of stack */ + return 1; +} + + static int ngx_http_lua_shdict_add(lua_State *L) { diff --git a/t/043-shdict.t b/t/043-shdict.t index 7c7451df2f..6d905ae2ef 100644 --- a/t/043-shdict.t +++ b/t/043-shdict.t @@ -1172,3 +1172,198 @@ GET /t --- response_body 0 + + +=== TEST 49: list all keys in a shdict +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + + dogs:set("bah", "y", 0) + dogs:set("bar", "z", 0) + local keys = dogs:get_keys() + ngx.say(#keys) + table.sort(keys) + for _,k in ipairs(keys) do + ngx.say(k) + end + '; + } +--- request +GET /t +--- response_body +2 +bah +bar + + + +=== TEST 50: list keys in a shdict with limit +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + + dogs:set("bah", "y", 0) + dogs:set("bar", "z", 0) + local keys = dogs:get_keys(1) + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +1 + + + +=== TEST 51: list all keys in a shdict with expires +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("foo", "x", 1) + dogs:set("bah", "y", 0) + dogs:set("bar", "z", 100) + + ngx.sleep(1.5) + + local keys = dogs:get_keys() + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +2 + + + +=== TEST 52: list keys in a shdict with limit larger than number of keys +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + + dogs:set("bah", "y", 0) + dogs:set("bar", "z", 0) + local keys = dogs:get_keys(3) + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +2 + + + +=== TEST 53: list keys in an empty shdict +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + local keys = dogs:get_keys() + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +0 + + + +=== TEST 54: list keys in an empty shdict with a limit +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + local keys = dogs:get_keys(4) + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +0 + + + +=== TEST 55: list all keys in a shdict with all keys expired +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + dogs:set("foo", "x", 1) + dogs:set("bah", "y", 1) + dogs:set("bar", "z", 1) + + ngx.sleep(1.5) + + local keys = dogs:get_keys() + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +0 + + + +=== TEST 56: list all keys in a shdict with more than 1024 keys with no limit set +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + for i=1,2048 do + dogs:set(tostring(i), i) + end + local keys = dogs:get_keys() + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +1024 + + + +=== TEST 57: list all keys in a shdict with more than 1024 keys with 0 limit set +--- http_config + lua_shared_dict dogs 1m; +--- config + location = /t { + content_by_lua ' + local dogs = ngx.shared.dogs + for i=1,2048 do + dogs:set(tostring(i), i) + end + local keys = dogs:get_keys(0) + ngx.say(#keys) + '; + } +--- request +GET /t +--- response_body +2048 + diff --git a/t/062-count.t b/t/062-count.t index 11e5a42345..848c7f2c6d 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -279,7 +279,7 @@ n = 4 --- request GET /test --- response_body -n = 9 +n = 10 --- no_error_log [error] From 7b1f3323a2ebc3a3cea528b5dcceedc5ecb5d5b4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 30 Oct 2012 17:12:17 -0700 Subject: [PATCH 0141/2239] documented the new shdict:get_keys() API. also bumped version to 0.7.3. --- README | 28 ++++++++++++++++++++++++---- README.markdown | 20 +++++++++++++++++--- doc/HttpLuaModule.wiki | 19 ++++++++++++++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/README b/README index c750119b7e..ee083713c6 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.2 - () released on 17 + This document describes ngx_lua v0.7.3 + () released on 30 October 2012. Synopsis @@ -115,7 +115,7 @@ Synopsis location /foo { rewrite_by_lua ' res = ngx.location.capture("/memc", - { args = { cmd = 'incr', key = ngx.var.uri } } + { args = { cmd = "incr", key = ngx.var.uri } } ) '; @@ -3955,6 +3955,26 @@ Nginx API for Lua See also ngx.shared.DICT.flush_all and ngx.shared.DICT. + 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** + + Fetch a list of the keys from the dictionary, up to "". + + By default, only the first 1024 keys (if any) are returned. When the + "" argument is given the value 0, then all the keys will be + returned even there is more than 1024 keys in the dictionary. + + WARNING Be careful when calling this method on dictionaries with a + really huge number of keys. This method may lock the dictionary for + quite a while and block all the nginx worker processes that are trying + to access the dictionary. + + This feature was first introduced in the "v0.7.3" release. + ngx.socket.udp syntax: *udpsock = ngx.socket.udp()* @@ -5661,5 +5681,5 @@ See Also * The ngx_openresty bundle () Translations - * Chinese + * Chinese (still in progress) diff --git a/README.markdown b/README.markdown index 6067b3ef6d..50303a0dee 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.2](https://github.com/chaoslawful/lua-nginx-module/tags) released on 17 October 2012. +This document describes ngx_lua [v0.7.3](https://github.com/chaoslawful/lua-nginx-module/tags) released on 30 October 2012. Synopsis ======== @@ -125,7 +125,7 @@ Synopsis location /foo { rewrite_by_lua ' res = ngx.location.capture("/memc", - { args = { cmd = 'incr', key = ngx.var.uri } } + { args = { cmd = "incr", key = ngx.var.uri } } ) '; @@ -3617,6 +3617,20 @@ 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). +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** + +Fetch a list of the keys from the dictionary, up to ``. + +By default, only the first 1024 keys (if any) are returned. When the `` argument is given the value `0`, then all the keys will be returned even there is more than 1024 keys in the dictionary. + +**WARNING** Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. + +This feature was first introduced in the `v0.7.3` release. + ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* @@ -4960,5 +4974,5 @@ See Also Translations ============ -* [Chinese](http://wiki.nginx.org/HttpLuaModuleZh) +* [Chinese](http://wiki.nginx.org/HttpLuaModuleZh) (still in progress) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 3ed596d895..2d63f9e2c9 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.2] released on 17 October 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.3] released on 30 October 2012. = Synopsis = @@ -116,7 +116,7 @@ This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module location /foo { rewrite_by_lua ' res = ngx.location.capture("/memc", - { args = { cmd = 'incr', key = ngx.var.uri } } + { args = { cmd = "incr", key = ngx.var.uri } } ) '; @@ -3494,6 +3494,19 @@ 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]]. +== 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*'' + +Fetch a list of the keys from the dictionary, up to . + +By default, only the first 1024 keys (if any) are returned. When the argument is given the value 0, then all the keys will be returned even there is more than 1024 keys in the dictionary. + +'''WARNING''' Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. + +This feature was first introduced in the v0.7.3 release. + == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' @@ -4784,5 +4797,5 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * [http://openresty.org The ngx_openresty bundle] = Translations = -* [[HttpLuaModuleZh|Chinese]] +* [[HttpLuaModuleZh|Chinese]] (still in progress) From 41243bfa876ddaf85b6ce0fee61f9c12cefd489d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 2 Nov 2012 15:48:35 -0700 Subject: [PATCH 0142/2239] code refactoring in the module configuration part. --- config | 2 - src/ngx_http_lua_common.h | 5 +- src/ngx_http_lua_conf.c | 264 ----------------------------------- src/ngx_http_lua_conf.h | 21 --- src/ngx_http_lua_directive.c | 1 - src/ngx_http_lua_module.c | 261 +++++++++++++++++++++++++++++++++- src/ngx_http_lua_shdict.c | 1 - 7 files changed, 263 insertions(+), 292 deletions(-) delete mode 100644 src/ngx_http_lua_conf.c delete mode 100644 src/ngx_http_lua_conf.h diff --git a/config b/config index eeb3bf37c4..aa123e35f2 100644 --- a/config +++ b/config @@ -165,7 +165,6 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_exception.c \ $ngx_addon_dir/src/ngx_http_lua_util.c \ $ngx_addon_dir/src/ngx_http_lua_cache.c \ - $ngx_addon_dir/src/ngx_http_lua_conf.c \ $ngx_addon_dir/src/ngx_http_lua_contentby.c \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.c \ $ngx_addon_dir/src/ngx_http_lua_accessby.c \ @@ -214,7 +213,6 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_exception.h \ $ngx_addon_dir/src/ngx_http_lua_util.h \ $ngx_addon_dir/src/ngx_http_lua_cache.h \ - $ngx_addon_dir/src/ngx_http_lua_conf.h \ $ngx_addon_dir/src/ngx_http_lua_contentby.h \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.h \ $ngx_addon_dir/src/ngx_http_lua_accessby.h \ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 426bffb87d..aa4b4ff65d 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -360,9 +360,11 @@ typedef struct ngx_http_lua_ctx_s { typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t; + typedef ngx_int_t (*ngx_http_lua_set_header_pt)(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); + struct ngx_http_lua_header_val_s { ngx_http_complex_value_t value; ngx_uint_t hash; @@ -372,10 +374,11 @@ struct ngx_http_lua_header_val_s { unsigned no_override; }; + typedef struct { ngx_str_t name; ngx_uint_t offset; - ngx_http_lua_set_header_pt handler; + ngx_http_lua_set_header_pt handler; } ngx_http_lua_set_header_t; diff --git a/src/ngx_http_lua_conf.c b/src/ngx_http_lua_conf.c deleted file mode 100644 index c333b08946..0000000000 --- a/src/ngx_http_lua_conf.c +++ /dev/null @@ -1,264 +0,0 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include -#include "ngx_http_lua_conf.h" -#include "ngx_http_lua_util.h" -#include "ngx_http_lua_probe.h" - - -static void ngx_http_lua_cleanup_vm(void *data); - - -void * -ngx_http_lua_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_lua_main_conf_t *lmcf; - - lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); - if (lmcf == NULL) { - return NULL; - } - - /* set by ngx_pcalloc: - * lmcf->lua = NULL; - * lmcf->lua_path = { 0, NULL }; - * lmcf->lua_cpath = { 0, NULL }; - * lmcf->regex_cache_entries = 0; - * lmcf->shm_zones = NULL; - * lmcf->init_handler = NULL; - * lmcf->init_src = { 0, NULL }; - * lmcf->shm_zones_inited = 0; - * lmcf->preload_hooks = NULL; - * lmcf->requires_header_filter = 0; - * lmcf->requires_body_filter = 0; - * lmcf->requires_capture_filter = 0; - * lmcf->requires_rewrite = 0; - * lmcf->requires_access = 0; - * lmcf->requires_log = 0; - * lmcf->requires_shm = 0; - */ - - lmcf->pool = cf->pool; -#if (NGX_PCRE) - lmcf->regex_cache_max_entries = NGX_CONF_UNSET; -#endif - lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; - - dd("nginx Lua module main config structure initialized!"); - - return lmcf; -} - - -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 (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { - lmcf->regex_cache_max_entries = 1024; - } -#endif - - return NGX_CONF_OK; -} - - -void * -ngx_http_lua_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_lua_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* set by ngx_pcalloc: - * conf->access_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->access_src_key = NULL - * conf->rewrite_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->rewrite_src_key = NULL - * conf->rewrite_handler = NULL; - * - * conf->content_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->content_src_key = NULL - * conf->content_handler = NULL; - * - * conf->log_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->log_src_key = NULL - * conf->log_handler = NULL; - * - * conf->header_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->header_filter_src_key = NULL - * conf->header_filter_handler = NULL; - * - * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->body_filter_src_key = NULL - * conf->body_filter_handler = NULL; - */ - - conf->force_read_body = NGX_CONF_UNSET; - conf->enable_code_cache = NGX_CONF_UNSET; - conf->http10_buffering = NGX_CONF_UNSET; - - conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; - conf->connect_timeout = NGX_CONF_UNSET_MSEC; - conf->send_timeout = NGX_CONF_UNSET_MSEC; - conf->read_timeout = NGX_CONF_UNSET_MSEC; - conf->send_lowat = NGX_CONF_UNSET_SIZE; - conf->buffer_size = NGX_CONF_UNSET_SIZE; - conf->pool_size = NGX_CONF_UNSET_UINT; - - conf->transform_underscores_in_resp_headers = NGX_CONF_UNSET; - conf->log_socket_errors = NGX_CONF_UNSET; - - return conf; -} - - -char * -ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_lua_loc_conf_t *prev = parent; - ngx_http_lua_loc_conf_t *conf = child; - - if (conf->rewrite_src.value.len == 0) { - conf->rewrite_src = prev->rewrite_src; - conf->rewrite_handler = prev->rewrite_handler; - conf->rewrite_src_key = prev->rewrite_src_key; - } - - if (conf->access_src.value.len == 0) { - conf->access_src = prev->access_src; - conf->access_handler = prev->access_handler; - conf->access_src_key = prev->access_src_key; - } - - if (conf->content_src.value.len == 0) { - conf->content_src = prev->content_src; - conf->content_handler = prev->content_handler; - conf->content_src_key = prev->content_src_key; - } - - if (conf->log_src.value.len == 0) { - conf->log_src = prev->log_src; - conf->log_handler = prev->log_handler; - conf->log_src_key = prev->log_src_key; - } - - if (conf->header_filter_src.value.len == 0) { - conf->header_filter_src = prev->header_filter_src; - conf->header_filter_handler = prev->header_filter_handler; - conf->header_filter_src_key = prev->header_filter_src_key; - } - - if (conf->body_filter_src.value.len == 0) { - conf->body_filter_src = prev->body_filter_src; - conf->body_filter_handler = prev->body_filter_handler; - conf->body_filter_src_key = prev->body_filter_src_key; - } - - ngx_conf_merge_value(conf->force_read_body, prev->force_read_body, 0); - 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_msec_value(conf->keepalive_timeout, - prev->keepalive_timeout, 60000); - - ngx_conf_merge_msec_value(conf->connect_timeout, - prev->connect_timeout, 60000); - - ngx_conf_merge_msec_value(conf->send_timeout, - prev->send_timeout, 60000); - - ngx_conf_merge_msec_value(conf->read_timeout, - prev->read_timeout, 60000); - - ngx_conf_merge_size_value(conf->send_lowat, - prev->send_lowat, 0); - - ngx_conf_merge_size_value(conf->buffer_size, - prev->buffer_size, - (size_t) ngx_pagesize); - - ngx_conf_merge_uint_value(conf->pool_size, prev->pool_size, 30); - - ngx_conf_merge_value(conf->transform_underscores_in_resp_headers, - prev->transform_underscores_in_resp_headers, 1); - - ngx_conf_merge_value(conf->log_socket_errors, prev->log_socket_errors, 1); - - return NGX_CONF_OK; -} - - -static void -ngx_http_lua_cleanup_vm(void *data) -{ - lua_State *L = data; - - if (L != NULL) { - lua_close(L); - - dd("Lua VM closed!"); - } -} - - -char * -ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) -{ - ngx_pool_cleanup_t *cln; - ngx_http_lua_preload_hook_t *hook; - lua_State *L; - ngx_uint_t i; - - /* add new cleanup handler to config mem pool */ - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_CONF_ERROR; - } - - /* create new Lua VM instance */ - lmcf->lua = ngx_http_lua_new_state(cf, lmcf); - if (lmcf->lua == NULL) { - return NGX_CONF_ERROR; - } - - /* register cleanup handler for Lua VM */ - cln->handler = ngx_http_lua_cleanup_vm; - cln->data = lmcf->lua; - - if (lmcf->preload_hooks) { - - /* register the 3rd-party module's preload hooks */ - - L = lmcf->lua; - - lua_getglobal(L, "package"); - lua_getfield(L, -1, "preload"); - - hook = lmcf->preload_hooks->elts; - - for (i = 0; i < lmcf->preload_hooks->nelts; i++) { - - ngx_http_lua_probe_register_preload_package(L, hook[i].package); - - lua_pushcfunction(L, hook[i].loader); - lua_setfield(L, -2, (char *) hook[i].package); - } - - lua_pop(L, 2); - } - - return NGX_CONF_OK; -} - diff --git a/src/ngx_http_lua_conf.h b/src/ngx_http_lua_conf.h deleted file mode 100644 index c449879633..0000000000 --- a/src/ngx_http_lua_conf.h +++ /dev/null @@ -1,21 +0,0 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ - -#ifndef NGX_HTTP_LUA_CONF_H -#define NGX_HTTP_LUA_CONF_H - -#include "ngx_http_lua_common.h" - - -void * ngx_http_lua_create_main_conf(ngx_conf_t *cf); - -char * ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); - -void * ngx_http_lua_create_loc_conf(ngx_conf_t *cf); - -char * ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); - -char * ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); - - -#endif /* NGX_HTTP_LUA_CONF_H */ diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 8c3c9046de..251431c441 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -10,7 +10,6 @@ #include "ngx_http_lua_directive.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_cache.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_rewriteby.h" diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index d135e105ec..bccf572225 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -6,15 +6,16 @@ #include "ddebug.h" #include "ngx_http_lua_directive.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_capturefilter.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_rewriteby.h" #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_logby.h" +#include "ngx_http_lua_util.h" #include "ngx_http_lua_headerfilterby.h" #include "ngx_http_lua_bodyfilterby.h" #include "ngx_http_lua_initby.h" +#include "ngx_http_lua_probe.h" #if !defined(nginx_version) || nginx_version < 8054 @@ -22,8 +23,15 @@ #endif +static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_lua_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); +static void ngx_http_lua_cleanup_vm(void *data); static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); -static char * ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); static ngx_conf_post_t ngx_http_lua_lowat_post = @@ -451,3 +459,252 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + +static void * +ngx_http_lua_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_lua_main_conf_t *lmcf; + + lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); + if (lmcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * lmcf->lua = NULL; + * lmcf->lua_path = { 0, NULL }; + * lmcf->lua_cpath = { 0, NULL }; + * lmcf->regex_cache_entries = 0; + * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; + * lmcf->shm_zones_inited = 0; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; + * lmcf->requires_capture_filter = 0; + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; + * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +#if (NGX_PCRE) + lmcf->regex_cache_max_entries = NGX_CONF_UNSET; +#endif + lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; + + dd("nginx Lua module main config structure initialized!"); + + return lmcf; +} + + +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 (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { + lmcf->regex_cache_max_entries = 1024; + } +#endif + + return NGX_CONF_OK; +} + + +static void * +ngx_http_lua_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_lua_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* set by ngx_pcalloc: + * conf->access_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->access_src_key = NULL + * conf->rewrite_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->rewrite_src_key = NULL + * conf->rewrite_handler = NULL; + * + * conf->content_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->content_src_key = NULL + * conf->content_handler = NULL; + * + * conf->log_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->log_src_key = NULL + * conf->log_handler = NULL; + * + * conf->header_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->header_filter_src_key = NULL + * conf->header_filter_handler = NULL; + * + * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->body_filter_src_key = NULL + * conf->body_filter_handler = NULL; + */ + + conf->force_read_body = NGX_CONF_UNSET; + conf->enable_code_cache = NGX_CONF_UNSET; + conf->http10_buffering = NGX_CONF_UNSET; + + conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; + conf->connect_timeout = NGX_CONF_UNSET_MSEC; + conf->send_timeout = NGX_CONF_UNSET_MSEC; + conf->read_timeout = NGX_CONF_UNSET_MSEC; + conf->send_lowat = NGX_CONF_UNSET_SIZE; + conf->buffer_size = NGX_CONF_UNSET_SIZE; + conf->pool_size = NGX_CONF_UNSET_UINT; + + conf->transform_underscores_in_resp_headers = NGX_CONF_UNSET; + conf->log_socket_errors = NGX_CONF_UNSET; + + + return conf; +} + + +static char * +ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_lua_loc_conf_t *prev = parent; + ngx_http_lua_loc_conf_t *conf = child; + + if (conf->rewrite_src.value.len == 0) { + conf->rewrite_src = prev->rewrite_src; + conf->rewrite_handler = prev->rewrite_handler; + conf->rewrite_src_key = prev->rewrite_src_key; + } + + if (conf->access_src.value.len == 0) { + conf->access_src = prev->access_src; + conf->access_handler = prev->access_handler; + conf->access_src_key = prev->access_src_key; + } + + if (conf->content_src.value.len == 0) { + conf->content_src = prev->content_src; + conf->content_handler = prev->content_handler; + conf->content_src_key = prev->content_src_key; + } + + if (conf->log_src.value.len == 0) { + conf->log_src = prev->log_src; + conf->log_handler = prev->log_handler; + conf->log_src_key = prev->log_src_key; + } + + if (conf->header_filter_src.value.len == 0) { + conf->header_filter_src = prev->header_filter_src; + conf->header_filter_handler = prev->header_filter_handler; + conf->header_filter_src_key = prev->header_filter_src_key; + } + + if (conf->body_filter_src.value.len == 0) { + conf->body_filter_src = prev->body_filter_src; + conf->body_filter_handler = prev->body_filter_handler; + conf->body_filter_src_key = prev->body_filter_src_key; + } + + ngx_conf_merge_value(conf->force_read_body, prev->force_read_body, 0); + 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_msec_value(conf->keepalive_timeout, + prev->keepalive_timeout, 60000); + + ngx_conf_merge_msec_value(conf->connect_timeout, + prev->connect_timeout, 60000); + + ngx_conf_merge_msec_value(conf->send_timeout, + prev->send_timeout, 60000); + + ngx_conf_merge_msec_value(conf->read_timeout, + prev->read_timeout, 60000); + + ngx_conf_merge_size_value(conf->send_lowat, + prev->send_lowat, 0); + + ngx_conf_merge_size_value(conf->buffer_size, + prev->buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_uint_value(conf->pool_size, prev->pool_size, 30); + + ngx_conf_merge_value(conf->transform_underscores_in_resp_headers, + prev->transform_underscores_in_resp_headers, 1); + + ngx_conf_merge_value(conf->log_socket_errors, prev->log_socket_errors, 1); + + return NGX_CONF_OK; +} + + +static void +ngx_http_lua_cleanup_vm(void *data) +{ + lua_State *L = data; + + if (L != NULL) { + lua_close(L); + + dd("Lua VM closed!"); + } +} + + +static char * +ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_lua_preload_hook_t *hook; + lua_State *L; + ngx_uint_t i; + + /* add new cleanup handler to config mem pool */ + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + /* create new Lua VM instance */ + lmcf->lua = ngx_http_lua_new_state(cf, lmcf); + if (lmcf->lua == NULL) { + return NGX_CONF_ERROR; + } + + /* register cleanup handler for Lua VM */ + cln->handler = ngx_http_lua_cleanup_vm; + cln->data = lmcf->lua; + + if (lmcf->preload_hooks) { + + /* register the 3rd-party module's preload hooks */ + + L = lmcf->lua; + + lua_getglobal(L, "package"); + lua_getfield(L, -1, "preload"); + + hook = lmcf->preload_hooks->elts; + + for (i = 0; i < lmcf->preload_hooks->nelts; i++) { + + ngx_http_lua_probe_register_preload_package(L, hook[i].package); + + lua_pushcfunction(L, hook[i].loader); + lua_setfield(L, -2, (char *) hook[i].package); + } + + lua_pop(L, 2); + } + + return NGX_CONF_OK; +} + diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 90c99e3d23..7aeda85eac 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -6,7 +6,6 @@ #include "ngx_http_lua_shdict.h" #include "ngx_http_lua_util.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_api.h" From 5cc8de8e7d6d432f081daf8acee2b335587d991c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 2 Nov 2012 15:48:35 -0700 Subject: [PATCH 0143/2239] code refactoring in the module configuration part. --- config | 2 - src/ngx_http_lua_common.h | 5 +- src/ngx_http_lua_conf.c | 264 ----------------------------------- src/ngx_http_lua_conf.h | 21 --- src/ngx_http_lua_directive.c | 1 - src/ngx_http_lua_module.c | 261 +++++++++++++++++++++++++++++++++- src/ngx_http_lua_shdict.c | 1 - 7 files changed, 263 insertions(+), 292 deletions(-) delete mode 100644 src/ngx_http_lua_conf.c delete mode 100644 src/ngx_http_lua_conf.h diff --git a/config b/config index ae7991efd9..6028f2d02e 100644 --- a/config +++ b/config @@ -177,7 +177,6 @@ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $ngx_addon_dir/src/ngx_http_lua_exception.c \ $ngx_addon_dir/src/ngx_http_lua_util.c \ $ngx_addon_dir/src/ngx_http_lua_cache.c \ - $ngx_addon_dir/src/ngx_http_lua_conf.c \ $ngx_addon_dir/src/ngx_http_lua_contentby.c \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.c \ $ngx_addon_dir/src/ngx_http_lua_accessby.c \ @@ -226,7 +225,6 @@ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ $ngx_addon_dir/src/ngx_http_lua_exception.h \ $ngx_addon_dir/src/ngx_http_lua_util.h \ $ngx_addon_dir/src/ngx_http_lua_cache.h \ - $ngx_addon_dir/src/ngx_http_lua_conf.h \ $ngx_addon_dir/src/ngx_http_lua_contentby.h \ $ngx_addon_dir/src/ngx_http_lua_rewriteby.h \ $ngx_addon_dir/src/ngx_http_lua_accessby.h \ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 426bffb87d..aa4b4ff65d 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -360,9 +360,11 @@ typedef struct ngx_http_lua_ctx_s { typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t; + typedef ngx_int_t (*ngx_http_lua_set_header_pt)(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value); + struct ngx_http_lua_header_val_s { ngx_http_complex_value_t value; ngx_uint_t hash; @@ -372,10 +374,11 @@ struct ngx_http_lua_header_val_s { unsigned no_override; }; + typedef struct { ngx_str_t name; ngx_uint_t offset; - ngx_http_lua_set_header_pt handler; + ngx_http_lua_set_header_pt handler; } ngx_http_lua_set_header_t; diff --git a/src/ngx_http_lua_conf.c b/src/ngx_http_lua_conf.c deleted file mode 100644 index c333b08946..0000000000 --- a/src/ngx_http_lua_conf.c +++ /dev/null @@ -1,264 +0,0 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ - -#ifndef DDEBUG -#define DDEBUG 0 -#endif -#include "ddebug.h" - - -#include -#include "ngx_http_lua_conf.h" -#include "ngx_http_lua_util.h" -#include "ngx_http_lua_probe.h" - - -static void ngx_http_lua_cleanup_vm(void *data); - - -void * -ngx_http_lua_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_lua_main_conf_t *lmcf; - - lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); - if (lmcf == NULL) { - return NULL; - } - - /* set by ngx_pcalloc: - * lmcf->lua = NULL; - * lmcf->lua_path = { 0, NULL }; - * lmcf->lua_cpath = { 0, NULL }; - * lmcf->regex_cache_entries = 0; - * lmcf->shm_zones = NULL; - * lmcf->init_handler = NULL; - * lmcf->init_src = { 0, NULL }; - * lmcf->shm_zones_inited = 0; - * lmcf->preload_hooks = NULL; - * lmcf->requires_header_filter = 0; - * lmcf->requires_body_filter = 0; - * lmcf->requires_capture_filter = 0; - * lmcf->requires_rewrite = 0; - * lmcf->requires_access = 0; - * lmcf->requires_log = 0; - * lmcf->requires_shm = 0; - */ - - lmcf->pool = cf->pool; -#if (NGX_PCRE) - lmcf->regex_cache_max_entries = NGX_CONF_UNSET; -#endif - lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; - - dd("nginx Lua module main config structure initialized!"); - - return lmcf; -} - - -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 (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { - lmcf->regex_cache_max_entries = 1024; - } -#endif - - return NGX_CONF_OK; -} - - -void * -ngx_http_lua_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_lua_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* set by ngx_pcalloc: - * conf->access_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->access_src_key = NULL - * conf->rewrite_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->rewrite_src_key = NULL - * conf->rewrite_handler = NULL; - * - * conf->content_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->content_src_key = NULL - * conf->content_handler = NULL; - * - * conf->log_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->log_src_key = NULL - * conf->log_handler = NULL; - * - * conf->header_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->header_filter_src_key = NULL - * conf->header_filter_handler = NULL; - * - * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; - * conf->body_filter_src_key = NULL - * conf->body_filter_handler = NULL; - */ - - conf->force_read_body = NGX_CONF_UNSET; - conf->enable_code_cache = NGX_CONF_UNSET; - conf->http10_buffering = NGX_CONF_UNSET; - - conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; - conf->connect_timeout = NGX_CONF_UNSET_MSEC; - conf->send_timeout = NGX_CONF_UNSET_MSEC; - conf->read_timeout = NGX_CONF_UNSET_MSEC; - conf->send_lowat = NGX_CONF_UNSET_SIZE; - conf->buffer_size = NGX_CONF_UNSET_SIZE; - conf->pool_size = NGX_CONF_UNSET_UINT; - - conf->transform_underscores_in_resp_headers = NGX_CONF_UNSET; - conf->log_socket_errors = NGX_CONF_UNSET; - - return conf; -} - - -char * -ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_lua_loc_conf_t *prev = parent; - ngx_http_lua_loc_conf_t *conf = child; - - if (conf->rewrite_src.value.len == 0) { - conf->rewrite_src = prev->rewrite_src; - conf->rewrite_handler = prev->rewrite_handler; - conf->rewrite_src_key = prev->rewrite_src_key; - } - - if (conf->access_src.value.len == 0) { - conf->access_src = prev->access_src; - conf->access_handler = prev->access_handler; - conf->access_src_key = prev->access_src_key; - } - - if (conf->content_src.value.len == 0) { - conf->content_src = prev->content_src; - conf->content_handler = prev->content_handler; - conf->content_src_key = prev->content_src_key; - } - - if (conf->log_src.value.len == 0) { - conf->log_src = prev->log_src; - conf->log_handler = prev->log_handler; - conf->log_src_key = prev->log_src_key; - } - - if (conf->header_filter_src.value.len == 0) { - conf->header_filter_src = prev->header_filter_src; - conf->header_filter_handler = prev->header_filter_handler; - conf->header_filter_src_key = prev->header_filter_src_key; - } - - if (conf->body_filter_src.value.len == 0) { - conf->body_filter_src = prev->body_filter_src; - conf->body_filter_handler = prev->body_filter_handler; - conf->body_filter_src_key = prev->body_filter_src_key; - } - - ngx_conf_merge_value(conf->force_read_body, prev->force_read_body, 0); - 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_msec_value(conf->keepalive_timeout, - prev->keepalive_timeout, 60000); - - ngx_conf_merge_msec_value(conf->connect_timeout, - prev->connect_timeout, 60000); - - ngx_conf_merge_msec_value(conf->send_timeout, - prev->send_timeout, 60000); - - ngx_conf_merge_msec_value(conf->read_timeout, - prev->read_timeout, 60000); - - ngx_conf_merge_size_value(conf->send_lowat, - prev->send_lowat, 0); - - ngx_conf_merge_size_value(conf->buffer_size, - prev->buffer_size, - (size_t) ngx_pagesize); - - ngx_conf_merge_uint_value(conf->pool_size, prev->pool_size, 30); - - ngx_conf_merge_value(conf->transform_underscores_in_resp_headers, - prev->transform_underscores_in_resp_headers, 1); - - ngx_conf_merge_value(conf->log_socket_errors, prev->log_socket_errors, 1); - - return NGX_CONF_OK; -} - - -static void -ngx_http_lua_cleanup_vm(void *data) -{ - lua_State *L = data; - - if (L != NULL) { - lua_close(L); - - dd("Lua VM closed!"); - } -} - - -char * -ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) -{ - ngx_pool_cleanup_t *cln; - ngx_http_lua_preload_hook_t *hook; - lua_State *L; - ngx_uint_t i; - - /* add new cleanup handler to config mem pool */ - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_CONF_ERROR; - } - - /* create new Lua VM instance */ - lmcf->lua = ngx_http_lua_new_state(cf, lmcf); - if (lmcf->lua == NULL) { - return NGX_CONF_ERROR; - } - - /* register cleanup handler for Lua VM */ - cln->handler = ngx_http_lua_cleanup_vm; - cln->data = lmcf->lua; - - if (lmcf->preload_hooks) { - - /* register the 3rd-party module's preload hooks */ - - L = lmcf->lua; - - lua_getglobal(L, "package"); - lua_getfield(L, -1, "preload"); - - hook = lmcf->preload_hooks->elts; - - for (i = 0; i < lmcf->preload_hooks->nelts; i++) { - - ngx_http_lua_probe_register_preload_package(L, hook[i].package); - - lua_pushcfunction(L, hook[i].loader); - lua_setfield(L, -2, (char *) hook[i].package); - } - - lua_pop(L, 2); - } - - return NGX_CONF_OK; -} - diff --git a/src/ngx_http_lua_conf.h b/src/ngx_http_lua_conf.h deleted file mode 100644 index c449879633..0000000000 --- a/src/ngx_http_lua_conf.h +++ /dev/null @@ -1,21 +0,0 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ - -#ifndef NGX_HTTP_LUA_CONF_H -#define NGX_HTTP_LUA_CONF_H - -#include "ngx_http_lua_common.h" - - -void * ngx_http_lua_create_main_conf(ngx_conf_t *cf); - -char * ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); - -void * ngx_http_lua_create_loc_conf(ngx_conf_t *cf); - -char * ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); - -char * ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); - - -#endif /* NGX_HTTP_LUA_CONF_H */ diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 8c3c9046de..251431c441 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -10,7 +10,6 @@ #include "ngx_http_lua_directive.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_cache.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_rewriteby.h" diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index d135e105ec..bccf572225 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -6,15 +6,16 @@ #include "ddebug.h" #include "ngx_http_lua_directive.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_capturefilter.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_rewriteby.h" #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_logby.h" +#include "ngx_http_lua_util.h" #include "ngx_http_lua_headerfilterby.h" #include "ngx_http_lua_bodyfilterby.h" #include "ngx_http_lua_initby.h" +#include "ngx_http_lua_probe.h" #if !defined(nginx_version) || nginx_version < 8054 @@ -22,8 +23,15 @@ #endif +static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_lua_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); +static void ngx_http_lua_cleanup_vm(void *data); static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); -static char * ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); static ngx_conf_post_t ngx_http_lua_lowat_post = @@ -451,3 +459,252 @@ ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + +static void * +ngx_http_lua_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_lua_main_conf_t *lmcf; + + lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); + if (lmcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * lmcf->lua = NULL; + * lmcf->lua_path = { 0, NULL }; + * lmcf->lua_cpath = { 0, NULL }; + * lmcf->regex_cache_entries = 0; + * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; + * lmcf->shm_zones_inited = 0; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; + * lmcf->requires_capture_filter = 0; + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; + * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +#if (NGX_PCRE) + lmcf->regex_cache_max_entries = NGX_CONF_UNSET; +#endif + lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET; + + dd("nginx Lua module main config structure initialized!"); + + return lmcf; +} + + +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 (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { + lmcf->regex_cache_max_entries = 1024; + } +#endif + + return NGX_CONF_OK; +} + + +static void * +ngx_http_lua_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_lua_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* set by ngx_pcalloc: + * conf->access_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->access_src_key = NULL + * conf->rewrite_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->rewrite_src_key = NULL + * conf->rewrite_handler = NULL; + * + * conf->content_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->content_src_key = NULL + * conf->content_handler = NULL; + * + * conf->log_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->log_src_key = NULL + * conf->log_handler = NULL; + * + * conf->header_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->header_filter_src_key = NULL + * conf->header_filter_handler = NULL; + * + * conf->body_filter_src = {{ 0, NULL }, NULL, NULL, NULL}; + * conf->body_filter_src_key = NULL + * conf->body_filter_handler = NULL; + */ + + conf->force_read_body = NGX_CONF_UNSET; + conf->enable_code_cache = NGX_CONF_UNSET; + conf->http10_buffering = NGX_CONF_UNSET; + + conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; + conf->connect_timeout = NGX_CONF_UNSET_MSEC; + conf->send_timeout = NGX_CONF_UNSET_MSEC; + conf->read_timeout = NGX_CONF_UNSET_MSEC; + conf->send_lowat = NGX_CONF_UNSET_SIZE; + conf->buffer_size = NGX_CONF_UNSET_SIZE; + conf->pool_size = NGX_CONF_UNSET_UINT; + + conf->transform_underscores_in_resp_headers = NGX_CONF_UNSET; + conf->log_socket_errors = NGX_CONF_UNSET; + + + return conf; +} + + +static char * +ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_lua_loc_conf_t *prev = parent; + ngx_http_lua_loc_conf_t *conf = child; + + if (conf->rewrite_src.value.len == 0) { + conf->rewrite_src = prev->rewrite_src; + conf->rewrite_handler = prev->rewrite_handler; + conf->rewrite_src_key = prev->rewrite_src_key; + } + + if (conf->access_src.value.len == 0) { + conf->access_src = prev->access_src; + conf->access_handler = prev->access_handler; + conf->access_src_key = prev->access_src_key; + } + + if (conf->content_src.value.len == 0) { + conf->content_src = prev->content_src; + conf->content_handler = prev->content_handler; + conf->content_src_key = prev->content_src_key; + } + + if (conf->log_src.value.len == 0) { + conf->log_src = prev->log_src; + conf->log_handler = prev->log_handler; + conf->log_src_key = prev->log_src_key; + } + + if (conf->header_filter_src.value.len == 0) { + conf->header_filter_src = prev->header_filter_src; + conf->header_filter_handler = prev->header_filter_handler; + conf->header_filter_src_key = prev->header_filter_src_key; + } + + if (conf->body_filter_src.value.len == 0) { + conf->body_filter_src = prev->body_filter_src; + conf->body_filter_handler = prev->body_filter_handler; + conf->body_filter_src_key = prev->body_filter_src_key; + } + + ngx_conf_merge_value(conf->force_read_body, prev->force_read_body, 0); + 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_msec_value(conf->keepalive_timeout, + prev->keepalive_timeout, 60000); + + ngx_conf_merge_msec_value(conf->connect_timeout, + prev->connect_timeout, 60000); + + ngx_conf_merge_msec_value(conf->send_timeout, + prev->send_timeout, 60000); + + ngx_conf_merge_msec_value(conf->read_timeout, + prev->read_timeout, 60000); + + ngx_conf_merge_size_value(conf->send_lowat, + prev->send_lowat, 0); + + ngx_conf_merge_size_value(conf->buffer_size, + prev->buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_uint_value(conf->pool_size, prev->pool_size, 30); + + ngx_conf_merge_value(conf->transform_underscores_in_resp_headers, + prev->transform_underscores_in_resp_headers, 1); + + ngx_conf_merge_value(conf->log_socket_errors, prev->log_socket_errors, 1); + + return NGX_CONF_OK; +} + + +static void +ngx_http_lua_cleanup_vm(void *data) +{ + lua_State *L = data; + + if (L != NULL) { + lua_close(L); + + dd("Lua VM closed!"); + } +} + + +static char * +ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_lua_preload_hook_t *hook; + lua_State *L; + ngx_uint_t i; + + /* add new cleanup handler to config mem pool */ + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_CONF_ERROR; + } + + /* create new Lua VM instance */ + lmcf->lua = ngx_http_lua_new_state(cf, lmcf); + if (lmcf->lua == NULL) { + return NGX_CONF_ERROR; + } + + /* register cleanup handler for Lua VM */ + cln->handler = ngx_http_lua_cleanup_vm; + cln->data = lmcf->lua; + + if (lmcf->preload_hooks) { + + /* register the 3rd-party module's preload hooks */ + + L = lmcf->lua; + + lua_getglobal(L, "package"); + lua_getfield(L, -1, "preload"); + + hook = lmcf->preload_hooks->elts; + + for (i = 0; i < lmcf->preload_hooks->nelts; i++) { + + ngx_http_lua_probe_register_preload_package(L, hook[i].package); + + lua_pushcfunction(L, hook[i].loader); + lua_setfield(L, -2, (char *) hook[i].package); + } + + lua_pop(L, 2); + } + + return NGX_CONF_OK; +} + diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index 4fd0c65c55..a61334bf5c 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -6,7 +6,6 @@ #include "ngx_http_lua_shdict.h" #include "ngx_http_lua_util.h" -#include "ngx_http_lua_conf.h" #include "ngx_http_lua_api.h" From 83f8f95542705305fd85dde55ada89dd1e4e644c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 3 Nov 2012 22:28:30 -0700 Subject: [PATCH 0144/2239] bugfix: receiving data on ngx.req.socket() did not return any errors when the request body got truncated; now we return the "closed" error (or "client aborted" when lua_on_client_abort is not configured as "ignore"). feature: implemented new config directive lua_on_client_abort which (atm) takes two possible values, "ignore" (the default) and "stop". --- src/ngx_http_lua_accessby.c | 10 +- src/ngx_http_lua_common.h | 8 + src/ngx_http_lua_contentby.c | 8 + src/ngx_http_lua_module.c | 28 +- src/ngx_http_lua_req_body.c | 14 +- src/ngx_http_lua_rewriteby.c | 12 +- src/ngx_http_lua_socket_tcp.c | 113 +++--- src/ngx_http_lua_socket_tcp.h | 3 +- src/ngx_http_lua_util.c | 177 ++++++++ src/ngx_http_lua_util.h | 4 + t/023-rewrite/client-abort.t | 714 +++++++++++++++++++++++++++++++++ t/024-access/client-abort.t | 714 +++++++++++++++++++++++++++++++++ t/100-client-abort.t | 736 ++++++++++++++++++++++++++++++++++ t/StapThread.pm | 4 + 14 files changed, 2489 insertions(+), 56 deletions(-) create mode 100644 t/023-rewrite/client-abort.t create mode 100644 t/024-access/client-abort.t create mode 100644 t/100-client-abort.t diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 5fb2094d9f..2e89ad3f16 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -222,6 +222,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; + ngx_http_lua_loc_conf_t *llcf; + /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); @@ -280,7 +282,11 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_ACCESS; - c = r->connection; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + } rc = ngx_http_lua_run_thread(L, r, ctx, 0); @@ -290,6 +296,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return rc; } + c = r->connection; + if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index aa4b4ff65d..df3db3264e 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -186,6 +186,7 @@ typedef struct { ngx_flag_t log_socket_errors; + ngx_uint_t on_client_abort; } ngx_http_lua_loc_conf_t; @@ -197,6 +198,13 @@ typedef enum { } ngx_http_lua_user_coro_op_t; +enum { + NGX_HTTP_LUA_CLIENT_ABORT_IGNORE = 0, + NGX_HTTP_LUA_CLIENT_ABORT_STOP = 1, + NGX_HTTP_LUA_CLIENT_ABORT_ERROR = 2 /* unused */ +}; + + typedef enum { NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */ NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 57d5c2a731..8d2c794b7d 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -27,6 +27,8 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; + ngx_http_lua_loc_conf_t *llcf; + dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -86,6 +88,12 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + } + rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index bccf572225..a7397dfd27 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -27,8 +27,9 @@ static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); static char *ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_lua_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); -static char *ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); + void *child); +static char *ngx_http_lua_init_vm(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); static void ngx_http_lua_cleanup_vm(void *data); static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -38,6 +39,16 @@ static ngx_conf_post_t ngx_http_lua_lowat_post = { ngx_http_lua_lowat_check }; +static ngx_conf_enum_t ngx_http_lua_on_client_abort_state[] = { + { ngx_string("ignore"), NGX_HTTP_LUA_CLIENT_ABORT_IGNORE }, + { ngx_string("stop"), NGX_HTTP_LUA_CLIENT_ABORT_STOP }, +#if 0 + { ngx_string("error"), NGX_HTTP_LUA_CLIENT_ABORT_ERROR }, +#endif + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_lua_cmds[] = { { ngx_string("lua_shared_dict"), @@ -308,9 +319,18 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, http10_buffering), NULL }, + { ngx_string("lua_on_client_abort"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_lua_loc_conf_t, on_client_abort), + ngx_http_lua_on_client_abort_state }, + ngx_null_command }; + ngx_http_module_t ngx_http_lua_module_ctx = { NULL, /* preconfiguration */ ngx_http_lua_init, /* postconfiguration */ @@ -553,6 +573,7 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) conf->force_read_body = NGX_CONF_UNSET; conf->enable_code_cache = NGX_CONF_UNSET; conf->http10_buffering = NGX_CONF_UNSET; + conf->on_client_abort = NGX_CONF_UNSET_UINT; conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; conf->connect_timeout = NGX_CONF_UNSET_MSEC; @@ -616,6 +637,9 @@ 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_uint_value(conf->on_client_abort, prev->on_client_abort, + NGX_HTTP_LUA_CLIENT_ABORT_IGNORE); + ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 60000); diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 6031a65b86..ed85d61c8e 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -26,6 +26,7 @@ static ngx_int_t ngx_http_lua_read_body_resume(ngx_http_request_t *r); static void ngx_http_lua_req_body_cleanup(void *data); + void ngx_http_lua_inject_req_body_api(lua_State *L) { @@ -145,6 +146,8 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; + ngx_http_lua_loc_conf_t *llcf; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua req body post read"); @@ -158,6 +161,15 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) coctx->cleanup = NULL; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + r->read_event_handler = ngx_http_block_reading; + + } else { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + } + if (ctx->entered_content_phase) { (void) ngx_http_lua_read_body_resume(r); @@ -1129,8 +1141,6 @@ ngx_http_lua_req_body_cleanup(void *data) return; } - r->read_event_handler = ngx_http_block_reading; - if (r->connection->read->timer_set) { ngx_del_timer(r->connection->read); } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index d58f5e109d..5b68d4549a 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -217,10 +217,12 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; lua_State *co; + ngx_int_t rc; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; - ngx_int_t rc; + + ngx_http_lua_loc_conf_t *llcf; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); @@ -279,7 +281,11 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE; - c = r->connection; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + } rc = ngx_http_lua_run_thread(L, r, ctx, 0); @@ -287,6 +293,8 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) return rc; } + c = r->connection; + if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 36b1928976..211afc1fe4 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -94,7 +94,6 @@ static ngx_int_t ngx_http_lua_socket_add_input_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); -static ngx_int_t ngx_http_lua_test_expect(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_tcp_socket_cleanup(void *data); @@ -921,6 +920,9 @@ ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r, } else if (u->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) { + lua_pushliteral(L, "client aborted"); + } else { if (u->socket_errno) { @@ -1097,6 +1099,10 @@ 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) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + u->waiting = 0; rc = ngx_http_lua_socket_tcp_read(r, u); @@ -1300,6 +1306,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ssize_t n; unsigned read; size_t preread = 0; + ngx_http_lua_loc_conf_t *llcf; c = u->peer.connection; rev = c->read; @@ -1319,16 +1326,19 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, rc = u->input_filter(u->input_filter_ctx, size); if (rc == NGX_OK) { + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket receive done: wait:%d, eof:%d, " "uri:\"%V?%V\"", (int) u->waiting, (int) u->eof, &r->uri, &r->args); +#if 1 if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } +#endif ngx_http_lua_socket_handle_success(r, u); return NGX_OK; @@ -1434,7 +1444,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket try to recv data %uz: \"%V?%V\"", - (int) size, &r->uri, &r->args); + size, &r->uri, &r->args); n = c->recv(c, b->last, size); @@ -1453,6 +1463,25 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, } if (n == 0) { + + if (u->is_downstream) { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + if (r->request_body->rest) { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_CLOSED); + return NGX_ERROR; + } + + } else { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); + return NGX_ERROR; + } + } + u->eof = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1476,11 +1505,13 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, } } +#if 1 if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); return NGX_ERROR; } +#endif if (rev->active) { ngx_add_timer(rev, u->read_timeout); @@ -1674,12 +1705,40 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, int n; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; + ngx_event_t *ev; + + ngx_http_lua_loc_conf_t *llcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket receive return value handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); +#if 1 + if (u->is_downstream) { + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + r->read_event_handler = ngx_http_block_reading; + + } else { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + + ev = r->connection->read; + + dd("rev active: %d", ev->active); + + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && !ev->active) { + if (ngx_add_event(ev, NGX_READ_EVENT, 0) != NGX_OK) { + lua_pushnil(L); + lua_pushliteral(L, "failed to add event"); + return 2; + } + } + } + } +#endif + if (u->ft_type) { dd("u->bufs_in: %p", u->bufs_in); @@ -2201,8 +2260,6 @@ ngx_http_lua_socket_tcp_finalize(ngx_http_request_t *r, } if (u->is_downstream) { - r->read_event_handler = ngx_http_block_reading; - if (r->connection->read->timer_set) { ngx_del_timer(r->connection->read); } @@ -2485,6 +2542,10 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) u->length = (size_t) bytes; u->rest = u->length; + if (u->is_downstream) { + r->read_event_handler = ngx_http_lua_req_socket_rev_handler; + } + u->waiting = 0; rc = ngx_http_lua_socket_tcp_read(r, u); @@ -2977,8 +3038,6 @@ ngx_http_lua_req_socket(lua_State *L) coctx->data = u; ctx->req_body_reader_co_ctx = coctx; - r->read_event_handler = ngx_http_lua_req_socket_rev_handler; - if (c->read->timer_set) { ngx_del_timer(c->read); } @@ -3793,48 +3852,6 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, } -static ngx_int_t -ngx_http_lua_test_expect(ngx_http_request_t *r) -{ - ngx_int_t n; - ngx_str_t *expect; - - if (r->expect_tested - || r->headers_in.expect == NULL - || r->http_version < NGX_HTTP_VERSION_11) - { - return NGX_OK; - } - - r->expect_tested = 1; - - expect = &r->headers_in.expect->value; - - if (expect->len != sizeof("100-continue") - 1 - || ngx_strncasecmp(expect->data, (u_char *) "100-continue", - sizeof("100-continue") - 1) - != 0) - { - return NGX_OK; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "send 100 Continue"); - - n = r->connection->send(r->connection, - (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, - sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); - - if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { - return NGX_OK; - } - - /* we assume that such small packet should be send successfully */ - - return NGX_ERROR; -} - - static ngx_int_t ngx_http_lua_socket_tcp_resume(ngx_http_request_t *r) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index f5a96707ce..ab30c8b2b3 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -11,7 +11,8 @@ #define NGX_HTTP_LUA_SOCKET_FT_RESOLVER 0x0008 #define NGX_HTTP_LUA_SOCKET_FT_BUFTOOSMALL 0x0010 #define NGX_HTTP_LUA_SOCKET_FT_NOMEM 0x0020 -#define NGX_HTTP_LUA_SOCKET_FT_PARTIALWRITE 0x0020 +#define NGX_HTTP_LUA_SOCKET_FT_PARTIALWRITE 0x0040 +#define NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT 0x0080 typedef struct ngx_http_lua_socket_tcp_upstream_s diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 8f34a48e1d..abce2166c0 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -86,6 +86,8 @@ static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread); 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 void ngx_http_lua_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev); #ifndef LUA_PATH_SEP @@ -2934,3 +2936,178 @@ ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r, coctx->zombie_child_threads = NULL; } + +static void +ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) +{ + int n; + char buf[1]; + ngx_err_t err; + ngx_int_t event; + ngx_connection_t *c; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http lua check client, write event:%d, \"%V\"", + ev->write, &r->uri); + + c = r->connection; + + if (c->error) { + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { + + event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT; + + if (ngx_del_event(ev, event, 0) != NGX_OK) { + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + + if (!ev->pending_eof) { + return; + } + + ev->eof = 1; + c->error = 1; + + if (ev->kq_errno) { + ev->error = 1; + } + + if (!u->cacheable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, + "kevent() reported that client prematurely closed " + "connection, so upstream connection is closed too"); + + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, + "kevent() reported that client prematurely closed " + "connection"); + + if (u->peer.connection == NULL) { + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + } + + return; + } + +#endif + + n = recv(c->fd, buf, 1, MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err, + "http lua recv(): %d", n); + + if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { + return; + } + + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { + dd("event is active"); + + event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT; + +#if 1 + if (ngx_del_event(ev, event, 0) != NGX_OK) { + dd("failed to del event"); + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } +#endif + } + + dd("HERE %d", (int) n); + + if (n > 0) { + return; + } + + if (n == -1) { + if (err == NGX_EAGAIN) { + dd("HERE"); + return; + } + + ev->error = 1; + + } else { /* n == 0 */ + err = 0; + } + + ev->eof = 1; + c->error = 1; + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "client prematurely closed connection"); + + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); +} + + +void +ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_lua_check_broken_connection(r, r->connection->read); +} + + +ngx_int_t +ngx_http_lua_test_expect(ngx_http_request_t *r) +{ + ngx_int_t n; + ngx_str_t *expect; + + if (r->expect_tested + || r->headers_in.expect == NULL + || r->http_version < NGX_HTTP_VERSION_11) + { + return NGX_OK; + } + + r->expect_tested = 1; + + expect = &r->headers_in.expect->value; + + if (expect->len != sizeof("100-continue") - 1 + || ngx_strncasecmp(expect->data, (u_char *) "100-continue", + sizeof("100-continue") - 1) + != 0) + { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "send 100 Continue"); + + n = r->connection->send(r->connection, + (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, + sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); + + if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { + return NGX_OK; + } + + /* we assume that such small packet should be send successfully */ + + return NGX_ERROR; +} + diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index fccf0f5ed7..fb6295f260 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -137,6 +137,10 @@ ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); +void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r); + +ngx_int_t ngx_http_lua_test_expect(ngx_http_request_t *r); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t new file mode 100644 index 0000000000..71ddf00d56 --- /dev/null +++ b/t/023-rewrite/client-abort.t @@ -0,0 +1,714 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 2: sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 3: sleep + ignore +--- config + location /t { + lua_on_client_abort ignore; + rewrite_by_lua ' + ngx.sleep(1) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- stap_wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 4: subrequest + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 5: subrequest + ignore +--- config + location /t { + lua_on_client_abort ignore; + rewrite_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +lua req cleanup +delete thread 1 + +--- stap_wait: 1.1 +--- timeout: 0.1 +--- ignore_response +--- error_log +bad things happen + + + +=== TEST 6: subrequest + stop (proxy, ignore client abort) +--- config + location = /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort on; + proxy_pass http://www.google.com:1234/; + } + + location = /sleep { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 7: subrequest + stop (proxy, check client abort) +--- config + location = /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort off; + proxy_pass http://www.google.com:1234/; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 8: need body on + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + lua_need_request_body on; + rewrite_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.req.read_body() + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 10: ngx.req.socket + receive() + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + sock:receive() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 11: ngx.req.socket + receive(N) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + sock:receive(5) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 12: ngx.req.socket + receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + ngx.sleep(1) + '; + content_by_lua return; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:lua check broken conn +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup|lua check broken conn +lua req cleanup +delete thread 1)$ + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 13: ngx.req.socket + m * receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + sock:receive(2) + sock:receive(1) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 14: ngx.req.socket + receiveuntil + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it(2) + it(3) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 16: cosocket + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.req.discard_body() + + local sock, err = ngx.socket.tcp() + if not sock then + ngx.log(ngx.ERR, "failed to get socket: ", err) + return + end + + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + local bytes, err = sock:send("blpop nonexist 2\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + return + end + + -- ngx.log(ngx.ERR, "about to receive") + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive query: ", err) + return + end + + ngx.log(ngx.ERR, "res: ", res) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 17: ngx.req.socket + receive n < content-length + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + error("bad") + '; + content_by_lua return; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 100\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +failed to receive: client aborted + + + +=== TEST 18: ngx.req.socket + receive n == content-length + stop +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.sleep(1) + error("bad") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 19: ngx.req.socket + receive n == content-length + ignore +--- config + location /t { + rewrite_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.say("done") + '; + content_by_lua return; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- shutdown: 1 +--- response_body +done +--- no_error_log +[error] + + + +=== TEST 20: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.req.read_body() + '; + content_by_lua return; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- shutdown: 1 +--- ignore_response +--- no_error_log +[error] + diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t new file mode 100644 index 0000000000..b5dac66e3c --- /dev/null +++ b/t/024-access/client-abort.t @@ -0,0 +1,714 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 2: sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 3: sleep + ignore +--- config + location /t { + lua_on_client_abort ignore; + access_by_lua ' + ngx.sleep(1) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- stap_wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 4: subrequest + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 5: subrequest + ignore +--- config + location /t { + lua_on_client_abort ignore; + access_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +lua req cleanup +delete thread 1 + +--- stap_wait: 1.1 +--- timeout: 0.1 +--- ignore_response +--- error_log +bad things happen + + + +=== TEST 6: subrequest + stop (proxy, ignore client abort) +--- config + location = /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort on; + proxy_pass http://www.google.com:1234/; + } + + location = /sleep { + lua_on_client_abort stop; + access_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 7: subrequest + stop (proxy, check client abort) +--- config + location = /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort off; + proxy_pass http://www.google.com:1234/; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 8: need body on + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + lua_need_request_body on; + access_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.req.read_body() + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 10: ngx.req.socket + receive() + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + sock:receive() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 11: ngx.req.socket + receive(N) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + sock:receive(5) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 12: ngx.req.socket + receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + ngx.sleep(1) + '; + content_by_lua return; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:lua check broken conn +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup|lua check broken conn +lua req cleanup +delete thread 1)$ + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 13: ngx.req.socket + m * receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + sock:receive(2) + sock:receive(1) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 14: ngx.req.socket + receiveuntil + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it(2) + it(3) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 16: cosocket + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.req.discard_body() + + local sock, err = ngx.socket.tcp() + if not sock then + ngx.log(ngx.ERR, "failed to get socket: ", err) + return + end + + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + local bytes, err = sock:send("blpop nonexist 2\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + return + end + + -- ngx.log(ngx.ERR, "about to receive") + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive query: ", err) + return + end + + ngx.log(ngx.ERR, "res: ", res) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 17: ngx.req.socket + receive n < content-length + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + error("bad") + '; + content_by_lua return; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 100\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +failed to receive: client aborted + + + +=== TEST 18: ngx.req.socket + receive n == content-length + stop +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.sleep(1) + error("bad") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 19: ngx.req.socket + receive n == content-length + ignore +--- config + location /t { + access_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.say("done") + '; + content_by_lua return; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- shutdown: 1 +--- response_body +done +--- no_error_log +[error] + + + +=== TEST 20: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.req.read_body() + '; + content_by_lua return; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- shutdown: 1 +--- ignore_response +--- no_error_log +[error] + diff --git a/t/100-client-abort.t b/t/100-client-abort.t new file mode 100644 index 0000000000..266ee3adde --- /dev/null +++ b/t/100-client-abort.t @@ -0,0 +1,736 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 2: sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 3: sleep + ignore +--- config + location /t { + lua_on_client_abort ignore; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- stap_wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 4: subrequest + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 5: subrequest + ignore +--- config + location /t { + lua_on_client_abort ignore; + content_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location /sub { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +lua req cleanup +delete thread 1 + +--- stap_wait: 1.1 +--- timeout: 0.1 +--- ignore_response +--- error_log +bad things happen + + + +=== TEST 6: subrequest + stop (proxy, ignore client abort) +--- config + location = /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort on; + proxy_pass http://www.google.com:1234/; + } + + location = /sleep { + lua_on_client_abort stop; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 7: subrequest + stop (proxy, check client abort) +--- config + location = /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.location.capture("/sub") + error("bad things happen") + '; + } + + location = /sub { + proxy_ignore_client_abort off; + proxy_pass http://www.google.com:1234/; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 8: need body on + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + lua_need_request_body on; + content_by_lua ' + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.req.read_body() + ngx.sleep(1) + '; + log_by_lua ' + ngx.log(ngx.NOTICE, "here in log by lua") + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +here in log by lua + + + +=== TEST 10: ngx.req.socket + receive() + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + sock:receive() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 11: ngx.req.socket + receive(N) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + sock:receive(5) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 12: ngx.req.socket + receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like +^(?:lua check broken conn +terminate 1: ok +delete thread 1 +lua req cleanup|lua check broken conn +lua req cleanup +delete thread 1)$ + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 13: ngx.req.socket + m * receive(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + sock:receive(2) + sock:receive(2) + sock:receive(1) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 14: ngx.req.socket + receiveuntil + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it() + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + local it = sock:receiveuntil("\\n") + it(2) + it(3) + ngx.sleep(1) + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 16: cosocket + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.req.discard_body() + + local sock, err = ngx.socket.tcp() + if not sock then + ngx.log(ngx.ERR, "failed to get socket: ", err) + return + end + + ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + local bytes, err = sock:send("blpop nonexist 2\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + return + end + + -- ngx.log(ngx.ERR, "about to receive") + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive query: ", err) + return + end + + ngx.log(ngx.ERR, "res: ", res) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- stap_wait: 1 +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 17: ngx.req.socket + receive n < content-length + ignore +--- config + location /t { + lua_on_client_abort ignore; + content_by_lua ' + local sock = ngx.req.socket() + local res, err, part = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err, ": ", part) + return + end + error("bad") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 100\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +failed to receive: closed: hello + + + +=== TEST 18: ngx.req.socket + receive n < content-length + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + local res, err, part = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err, ": ", part) + return + end + error("bad") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 100\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +failed to receive: client aborted: hello + + + +=== TEST 19: ngx.req.socket + receive n == content-length + stop +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.sleep(1) + error("bad") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +lua check broken conn +lua req cleanup +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection + + + +=== TEST 20: ngx.req.socket + receive n == content-length + ignore +--- config + location /t { + content_by_lua ' + local sock = ngx.req.socket() + local res, err = sock:receive("*a") + if not res then + ngx.log(ngx.NOTICE, "failed to receive: ", err) + return + end + ngx.say("done") + '; + } +--- raw_request eval +"POST /t HTTP/1.0\r +Host: localhost\r +Connection: close\r +Content-Length: 5\r +\r +hello" +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- shutdown: 1 +--- response_body +done +--- no_error_log +[error] + + + +=== TEST 21: ngx.req.read_body + sleep + stop (log handler still gets called) +--- config + location /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.req.read_body() + '; + } +--- request +POST /t +hello + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- shutdown: 1 +--- ignore_response +--- no_error_log +[error] + diff --git a/t/StapThread.pm b/t/StapThread.pm index 25290144b2..1283854062 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -64,6 +64,9 @@ function gen_id(k) { F(ngx_http_init_request) { in_req++ + + printf("in req: %d\n", in_req) + if (in_req == 1) { delete ids cur = 0 @@ -76,6 +79,7 @@ F(ngx_http_init_request) { F(ngx_http_free_request) { in_req-- + println("free request") } F(ngx_http_lua_post_thread) { From c5dc5dc14752bff149e4c0268f41c7b05fc9f7a1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 00:11:15 -0700 Subject: [PATCH 0145/2239] bugfix: reading on ngx.req.socket() now returns the error "client aborted" in case request body truncation even when lua_on_client_abort is "ignore". bugfix: for edge-triggered events, use of ngx.req.socket() might prevent "lua_on_client_abort stop" from detecting the connection shutdown event. --- src/ngx_http_lua_socket_tcp.c | 32 +++++++++++++++++++- src/ngx_http_lua_util.c | 56 +++++++++++++---------------------- src/ngx_http_lua_util.h | 4 +++ t/023-rewrite/client-abort.t | 4 +++ t/024-access/client-abort.t | 4 +++ t/100-client-abort.t | 29 ++++++++++++------ 6 files changed, 84 insertions(+), 45 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 211afc1fe4..b15f783288 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1332,6 +1332,35 @@ 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 + && b->last == b->pos + && r->request_body->rest == 0) + { + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + + if (llcf->on_client_abort != + NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) + { + rc = ngx_http_lua_check_broken_connection(r, rev); + + if (rc == NGX_OK) { + goto success; + } + + if (rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); + + } else { + ngx_http_lua_socket_handle_error(r, u, + NGX_HTTP_LUA_SOCKET_FT_ERROR); + } + + return NGX_ERROR; + } + } + #if 1 if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_lua_socket_handle_error(r, u, @@ -1340,6 +1369,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, } #endif +success: ngx_http_lua_socket_handle_success(r, u); return NGX_OK; } @@ -1471,7 +1501,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { if (r->request_body->rest) { ngx_http_lua_socket_handle_error(r, u, - NGX_HTTP_LUA_SOCKET_FT_CLOSED); + NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); return NGX_ERROR; } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index abce2166c0..9e45a7d561 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -86,8 +86,6 @@ static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread); 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 void ngx_http_lua_check_broken_connection(ngx_http_request_t *r, - ngx_event_t *ev); #ifndef LUA_PATH_SEP @@ -2937,7 +2935,7 @@ ngx_http_lua_cleanup_zombie_child_uthreads(ngx_http_request_t *r, } -static void +ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) { int n; @@ -2958,15 +2956,11 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT; if (ngx_del_event(ev, event, 0) != NGX_OK) { - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; + return NGX_HTTP_CLIENT_CLOSED_REQUEST; } #if (NGX_HAVE_KQUEUE) @@ -2984,26 +2978,11 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) ev->error = 1; } - if (!u->cacheable && u->peer.connection) { - ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, - "kevent() reported that client prematurely closed " - "connection, so upstream connection is closed too"); - - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, "kevent() reported that client prematurely closed " "connection"); - if (u->peer.connection == NULL) { - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); - } - - return; + return NGX_HTTP_CLIENT_CLOSED_REQUEST; } #endif @@ -3016,7 +2995,7 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) "http lua recv(): %d", n); if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { - return; + return NGX_OK; } if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { @@ -3026,10 +3005,7 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) #if 1 if (ngx_del_event(ev, event, 0) != NGX_OK) { - dd("failed to del event"); - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } #endif } @@ -3037,13 +3013,13 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) dd("HERE %d", (int) n); if (n > 0) { - return; + return NGX_OK; } if (n == -1) { if (err == NGX_EAGAIN) { dd("HERE"); - return; + return NGX_OK; } ev->error = 1; @@ -3058,15 +3034,25 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) ngx_log_error(NGX_LOG_INFO, ev->log, err, "client prematurely closed connection"); - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + return NGX_HTTP_CLIENT_CLOSED_REQUEST; } void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) { - ngx_http_lua_check_broken_connection(r, r->connection->read); + ngx_int_t rc; + + rc = ngx_http_lua_check_broken_connection(r, r->connection->read); + + if (rc == NGX_OK) { + return; + } + + /* rc == NGX_ERROR || rc > NGX_OK */ + + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, rc); } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index fb6295f260..b32b8be976 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -141,6 +141,10 @@ void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r); 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); + + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 71ddf00d56..bcfd6080dd 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -369,6 +369,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -436,6 +437,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -501,6 +503,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -635,6 +638,7 @@ hello" --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index b5dac66e3c..0e078f471c 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -369,6 +369,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -436,6 +437,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -501,6 +503,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -635,6 +638,7 @@ hello" --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 266ee3adde..56b53edac4 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'; @@ -366,6 +366,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -430,6 +431,7 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 @@ -495,10 +497,11 @@ hello --- stap eval: $::GCScript --- stap_out lua check broken conn +lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.2 +--- timeout: 0.1 --- ignore_response --- no_error_log [error] @@ -596,7 +599,7 @@ lua req cleanup --- no_error_log [error] --- error_log -failed to receive: closed: hello +failed to receive: client aborted: hello @@ -648,7 +651,7 @@ failed to receive: client aborted: hello ngx.log(ngx.NOTICE, "failed to receive: ", err) return end - ngx.sleep(1) + ngx.sleep(0.1) error("bad") '; } @@ -659,14 +662,19 @@ Connection: close\r Content-Length: 5\r \r hello" + --- stap2 eval: $::StapScript --- stap eval: $::GCScript ---- stap_out +--- stap_out_like +^(?:lua check broken conn +terminate 1: ok +delete thread 1 +lua req cleanup|lua check broken conn lua check broken conn lua req cleanup -delete thread 1 +delete thread 1)$ ---- timeout: 0.1 +--- shutdown --- ignore_response --- no_error_log [error] @@ -716,6 +724,7 @@ done lua_on_client_abort stop; content_by_lua ' ngx.req.read_body() + ngx.sleep(0.1) '; } --- request @@ -725,12 +734,14 @@ hello --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -terminate 1: ok -delete thread 1 +lua check broken conn lua req cleanup +delete thread 1 --- shutdown: 1 --- ignore_response --- no_error_log [error] +--- error_log +client prematurely closed connection From 1937d581121d8436c63a4bc4f2034dcea5706dd0 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 15:38:45 -0800 Subject: [PATCH 0146/2239] updated --- stap_wait to --- wait in the test suite to reflect the new changes in Test::Nginx::Socket. --- t/023-rewrite/client-abort.t | 12 ++++++------ t/024-access/client-abort.t | 12 ++++++------ t/100-client-abort.t | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index bcfd6080dd..3d4a9d9f64 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -111,7 +111,7 @@ terminate 2: ok delete thread 2 lua req cleanup ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -174,7 +174,7 @@ terminate 1: fail lua req cleanup delete thread 1 ---- stap_wait: 1.1 +--- wait: 1.1 --- timeout: 0.1 --- ignore_response --- error_log @@ -409,7 +409,7 @@ lua req cleanup|lua check broken conn lua req cleanup delete thread 1)$ ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -441,7 +441,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -473,7 +473,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -562,7 +562,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 0e078f471c..cb10923cc1 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -111,7 +111,7 @@ terminate 2: ok delete thread 2 lua req cleanup ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -174,7 +174,7 @@ terminate 1: fail lua req cleanup delete thread 1 ---- stap_wait: 1.1 +--- wait: 1.1 --- timeout: 0.1 --- ignore_response --- error_log @@ -409,7 +409,7 @@ lua req cleanup|lua check broken conn lua req cleanup delete thread 1)$ ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -441,7 +441,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -473,7 +473,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -562,7 +562,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 56b53edac4..639f00dd9e 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -108,7 +108,7 @@ terminate 1: ok delete thread 1 lua req cleanup ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -171,7 +171,7 @@ terminate 1: fail lua req cleanup delete thread 1 ---- stap_wait: 1.1 +--- wait: 1.1 --- timeout: 0.1 --- ignore_response --- error_log @@ -403,7 +403,7 @@ lua req cleanup|lua check broken conn lua req cleanup delete thread 1)$ ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -435,7 +435,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -467,7 +467,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log @@ -556,7 +556,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- stap_wait: 1 +--- wait: 1 --- timeout: 0.2 --- ignore_response --- no_error_log From 31089a419c893eca107c293519b22c49dcbc927b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 20:37:55 -0800 Subject: [PATCH 0147/2239] bugfix: we could not compile on FreeBSD due to the recent work on lua_on_client_abort. --- src/ngx_http_lua_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 9e45a7d561..91b3ff11f6 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2968,7 +2968,7 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { if (!ev->pending_eof) { - return; + return NGX_OK; } ev->eof = 1; From 92058483d569b1c7bb8e1d48c5eeefd9591a95eb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 20:43:24 -0800 Subject: [PATCH 0148/2239] bugfix: ngx_lua cosocket's connect() method could not detect errors like "connection refused" when kqueue was used. tests: fixed the compatibilty issues in those test cases that were failing on non-Linux systems like FreeBSD. --- src/ngx_http_lua_setby.c | 2 ++ src/ngx_http_lua_socket_tcp.c | 25 ++++++++++++++++++++----- t/023-rewrite/tcp-socket.t | 10 +++++----- t/058-tcp-socket.t | 12 ++++++------ t/087-udp-socket.t | 4 ++-- t/100-client-abort.t | 1 + 6 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 49d8b04570..08748b0728 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -98,6 +98,8 @@ ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, rc = lua_pcall(L, nargs, 1, 1); + dd("after protected call user code"); + lua_remove(L, 1); /* remove traceback function */ #if (NGX_PCRE) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index b15f783288..84f38f2ca9 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2335,16 +2335,31 @@ 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) { - int err; - socklen_t len; + int err; + socklen_t len; + ngx_event_t *ev; #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + dd("pending eof: (%p)%d (%p)%d", c->write, c->write->pending_eof, + c->read, c->read->pending_eof); + if (c->write->pending_eof) { - (void) ngx_connection_error(c, c->write->kq_errno, - "kevent() reported that connect() failed"); - return NGX_ERROR; + ev = c->write; + + } else if (c->read->pending_eof) { + ev = c->read; + + } else { + ev = NULL; + } + + if (ev) { + (void) ngx_connection_error(c, ev->kq_errno, + "kevent() reported that connect() " + "failed"); + return ev->kq_errno; } } else diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 776c828e86..200fd79244 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -291,8 +291,8 @@ connect: nil connection refused send: nil closed receive: nil closed close: nil closed ---- error_log -connect() failed (111: Connection refused) +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ @@ -447,7 +447,7 @@ attempt to send data on a closed socket --- request GET /t --- response_body_like -^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(110: Operation timed out\))? +^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(\d+: Operation timed out\))? connected: nil failed to send request: closed$ --- error_log @@ -1000,8 +1000,8 @@ close: nil closed GET /test --- response_body failed to connect: connection refused ---- error_log -connect() failed (111: Connection refused) +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 163e7ea906..c665e2fdd6 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -3,7 +3,7 @@ use lib 'lib'; use Test::Nginx::Socket; -repeat_each(2); +#repeat_each(2); plan tests => repeat_each() * 87; @@ -284,8 +284,8 @@ connect: nil connection refused send: nil closed receive: nil closed close: nil closed ---- error_log -connect() failed (111: Connection refused) +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ @@ -432,7 +432,7 @@ attempt to send data on a closed socket --- request GET /t --- response_body_like -^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(110: Operation timed out\))? +^failed to connect: blah-blah-not-found\.agentzh\.org could not be resolved(?: \(\d+: Operation timed out\))? connected: nil failed to send request: closed$ --- error_log @@ -976,8 +976,8 @@ M(http-lua-info) { --- response_body failed to connect: connection refused ---- error_log -connect() failed (111: Connection refused) +--- error_log eval +qr/connect\(\) failed \(\d+: Connection refused\)/ diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index be8af2800c..213814a439 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -188,8 +188,8 @@ GET /t --- response_body connected failed to receive data: connection refused ---- error_log -recv() failed (111: Connection refused) +--- error_log eval +qr/recv\(\) failed \(\d+: Connection refused\)/ diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 639f00dd9e..6937b0a09e 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -744,4 +744,5 @@ delete thread 1 [error] --- error_log client prematurely closed connection +--- SKIP From 9649c8ba6b097bb463843c5979f467b674385478 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 20:47:01 -0800 Subject: [PATCH 0149/2239] bugfix: fixed the -Werror=unused-variable gcc warning on systems without kqueue, which was introduced by commit 9205848. --- src/ngx_http_lua_socket_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 84f38f2ca9..5274cf45cf 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2337,10 +2337,11 @@ ngx_http_lua_socket_test_connect(ngx_connection_t *c) { int err; socklen_t len; - ngx_event_t *ev; #if (NGX_HAVE_KQUEUE) + ngx_event_t *ev; + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { dd("pending eof: (%p)%d (%p)%d", c->write, c->write->pending_eof, c->read, c->read->pending_eof); From 8f8cb23f36dd00af1b4467d2553953215717becd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 4 Nov 2012 22:44:51 -0800 Subject: [PATCH 0150/2239] bugfix: using "lua_on_client_abort stop" and doing internal redirects might lead to segmentation faults. --- src/ngx_http_lua_accessby.c | 3 + src/ngx_http_lua_contentby.c | 3 + src/ngx_http_lua_rewriteby.c | 3 + src/ngx_http_lua_util.c | 18 +++++- t/023-rewrite/client-abort.t | 110 ++++++++++++++++++++++++++++++++++ t/024-access/client-abort.t | 110 ++++++++++++++++++++++++++++++++++ t/100-client-abort.t | 111 ++++++++++++++++++++++++++++++++++- 7 files changed, 354 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 2e89ad3f16..af1371cf67 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -286,6 +286,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + + } else { + r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 8d2c794b7d..a73d601497 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -92,6 +92,9 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + + } else { + r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 5b68d4549a..b24fc992c3 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -285,6 +285,9 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + + } else { + r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 91b3ff11f6..acb7b83bfe 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2003,6 +2003,14 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, r->write_event_handler = ngx_http_request_empty_handler; +#if 1 + if (r->read_event_handler == ngx_http_lua_rd_check_broken_connection) { + /* resume the read event handler */ + + r->read_event_handler = ngx_http_block_reading; + } +#endif + #if 1 /* clear the modules contexts */ ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); @@ -2030,11 +2038,15 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r, dd("internal redirect to %.*s", (int) ctx->exec_uri.len, ctx->exec_uri.data); - /* resume the write event handler */ r->write_event_handler = ngx_http_request_empty_handler; - rc = ngx_http_internal_redirect(r, &ctx->exec_uri, - &ctx->exec_args); + if (r->read_event_handler == ngx_http_lua_rd_check_broken_connection) { + /* resume the read event handler */ + + r->read_event_handler = ngx_http_block_reading; + } + + rc = ngx_http_internal_redirect(r, &ctx->exec_uri, &ctx->exec_args); dd("internal redirect returned %d when in content phase? " "%d", (int) rc, ctx->entered_content_phase); diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 3d4a9d9f64..d0dafbfbb6 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -50,6 +50,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -716,3 +717,112 @@ lua req cleanup --- no_error_log [error] + + +=== TEST 21: exec to lua + ignore +--- config + location = /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + lua_on_client_abort ignore; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + + + +=== TEST 22: exec to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + + + +=== TEST 23: exec (named location) to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + rewrite_by_lua ' + ngx.exec("@t2") + '; + } + + location @t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index cb10923cc1..cb6467dd04 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -50,6 +50,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -716,3 +717,112 @@ lua req cleanup --- no_error_log [error] + + +=== TEST 21: exec to lua + ignore +--- config + location = /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + lua_on_client_abort ignore; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + + + +=== TEST 22: exec to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + + + +=== TEST 23: exec (named location) to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + access_by_lua ' + ngx.exec("@t2") + '; + } + + location @t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 6937b0a09e..3b57505e96 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 + 1); +plan tests => repeat_each() * (blocks() * 3); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -308,6 +308,7 @@ lua check broken conn lua req cleanup delete thread 1 +--- wait: 0.1 --- timeout: 0.1 --- ignore_response --- no_error_log @@ -746,3 +747,111 @@ delete thread 1 client prematurely closed connection --- SKIP + + +=== TEST 22: exec to lua + ignore +--- config + location = /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + lua_on_client_abort ignore; + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] + + + +=== TEST 23: exec to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.exec("/t2") + '; + } + + location = /t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + + + +=== TEST 24: exec (named location) to proxy + ignore +--- config + location = /t { + lua_on_client_abort stop; + content_by_lua ' + ngx.exec("@t2") + '; + } + + location @t2 { + proxy_ignore_client_abort on; + proxy_pass http://127.0.0.1:$server_port/sleep; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +lua req cleanup +delete thread 1 + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + From 8ed15a432b3f414e1867005966a519b1d18b843f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 5 Nov 2012 16:10:11 -0800 Subject: [PATCH 0151/2239] tweaked the test cases for one-way shutdown for the mockegain writing testing mode because nginx does not really support the one-way shutdown on the client side. --- t/023-rewrite/client-abort.t | 6 +++--- t/024-access/client-abort.t | 6 +++--- t/100-client-abort.t | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index d0dafbfbb6..1958c4eedd 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/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'; @@ -683,10 +683,10 @@ delete thread 2 lua req cleanup --- shutdown: 1 ---- response_body -done +--- ignore_response --- no_error_log [error] +[alert] diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index cb6467dd04..f634982e36 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/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'; @@ -683,10 +683,10 @@ delete thread 2 lua req cleanup --- shutdown: 1 ---- response_body -done +--- ignore_response --- no_error_log [error] +[alert] diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 3b57505e96..8bad4bbcde 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'; @@ -712,10 +712,10 @@ delete thread 1 lua req cleanup --- shutdown: 1 ---- response_body -done +--- ignore_response --- no_error_log [error] +[alert] From 5ba9195e59dcc85c253f867a8e0f12d0c734610c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 5 Nov 2012 16:36:10 -0800 Subject: [PATCH 0152/2239] fixed a test case regarding cosocket set_keepalive on FreeBSD. --- t/071-idle-socket.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index 033af95cc8..55c9755b2c 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -359,17 +359,17 @@ close: 1 nil } --- request GET /t ---- response_body eval -qq{connected: 1 +--- response_body_like eval +qr{connected: 1 request sent: 57 -read: HTTP/1.1 200 OK\r +read: HTTP/1\.1 200 OK\r Server: nginx\r Content-Type: text/plain\r Transfer-Encoding: chunked\r Connection: close\r \r 6\r -failed to set keepalive: connection in dubious state +failed to set keepalive: (?:unread data in buffer|connection in dubious state) } --- no_error_log [error] From ec5214cfcaed398cbcca7b801f1eebe607f0b156 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 5 Nov 2012 21:35:44 -0800 Subject: [PATCH 0153/2239] added a test case for testing the kqueue-specific bug in the ngx_http_upstream_test_connect function of the nginx core. --- t/100-client-abort.t | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 8bad4bbcde..7b4335404d 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 - 1); +plan tests => repeat_each() * (blocks() * 3); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -855,3 +855,19 @@ delete thread 1 [error] [alert] + + +=== TEST 25: bug in ngx_http_upstream_test_connect for kqueue +--- config + location /t { + proxy_pass http://127.0.0.1:1234/; + } +--- request +GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log eval +qr{connect\(\) failed \(\d+: Connection refused\) while connecting to upstream} +--- no_error_log +[alert] + From 52e971cb0c3a2db2bd4468f04d33fa8190e3631d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 6 Nov 2012 16:55:25 -0800 Subject: [PATCH 0154/2239] renamed the config directive "lua_on_client_abort stop|ignore" to "lua_check_client_abort on|off". --- src/ngx_http_lua_accessby.c | 2 +- src/ngx_http_lua_common.h | 11 +---- src/ngx_http_lua_contentby.c | 2 +- src/ngx_http_lua_module.c | 32 +++++---------- src/ngx_http_lua_req_body.c | 6 +-- src/ngx_http_lua_rewriteby.c | 2 +- src/ngx_http_lua_socket_tcp.c | 26 ++++++------ t/023-rewrite/client-abort.t | 48 +++++++++++----------- t/024-access/client-abort.t | 48 +++++++++++----------- t/100-client-abort.t | 76 +++++++++++++++++++++++------------ 10 files changed, 130 insertions(+), 123 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index af1371cf67..710dba3024 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -284,7 +284,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index df3db3264e..078dfb6b18 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -183,10 +183,8 @@ typedef struct { ngx_uint_t pool_size; ngx_flag_t transform_underscores_in_resp_headers; - ngx_flag_t log_socket_errors; - - ngx_uint_t on_client_abort; + ngx_flag_t check_client_abort; } ngx_http_lua_loc_conf_t; @@ -198,13 +196,6 @@ typedef enum { } ngx_http_lua_user_coro_op_t; -enum { - NGX_HTTP_LUA_CLIENT_ABORT_IGNORE = 0, - NGX_HTTP_LUA_CLIENT_ABORT_STOP = 1, - NGX_HTTP_LUA_CLIENT_ABORT_ERROR = 2 /* unused */ -}; - - typedef enum { NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */ NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index a73d601497..3239382770 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -90,7 +90,7 @@ ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index a7397dfd27..0f9894a966 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -39,16 +39,6 @@ static ngx_conf_post_t ngx_http_lua_lowat_post = { ngx_http_lua_lowat_check }; -static ngx_conf_enum_t ngx_http_lua_on_client_abort_state[] = { - { ngx_string("ignore"), NGX_HTTP_LUA_CLIENT_ABORT_IGNORE }, - { ngx_string("stop"), NGX_HTTP_LUA_CLIENT_ABORT_STOP }, -#if 0 - { ngx_string("error"), NGX_HTTP_LUA_CLIENT_ABORT_ERROR }, -#endif - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_http_lua_cmds[] = { { ngx_string("lua_shared_dict"), @@ -319,13 +309,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, http10_buffering), NULL }, - { ngx_string("lua_on_client_abort"), + { ngx_string("lua_check_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + |NGX_CONF_FLAG, + ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_lua_loc_conf_t, on_client_abort), - ngx_http_lua_on_client_abort_state }, + offsetof(ngx_http_lua_loc_conf_t, check_client_abort), + NULL }, ngx_null_command }; @@ -570,10 +560,10 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf) * conf->body_filter_handler = NULL; */ - conf->force_read_body = NGX_CONF_UNSET; - conf->enable_code_cache = NGX_CONF_UNSET; - conf->http10_buffering = NGX_CONF_UNSET; - conf->on_client_abort = NGX_CONF_UNSET_UINT; + conf->force_read_body = NGX_CONF_UNSET; + conf->enable_code_cache = NGX_CONF_UNSET; + conf->http10_buffering = NGX_CONF_UNSET; + conf->check_client_abort = NGX_CONF_UNSET; conf->keepalive_timeout = NGX_CONF_UNSET_MSEC; conf->connect_timeout = NGX_CONF_UNSET_MSEC; @@ -636,9 +626,7 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->force_read_body, prev->force_read_body, 0); 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_uint_value(conf->on_client_abort, prev->on_client_abort, - NGX_HTTP_LUA_CLIENT_ABORT_IGNORE); + ngx_conf_merge_value(conf->check_client_abort, prev->check_client_abort, 0); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 60000); diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index ed85d61c8e..c689dcbaa5 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -163,11 +163,11 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { - r->read_event_handler = ngx_http_block_reading; + if (llcf->check_client_abort) { + r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { - r->read_event_handler = ngx_http_lua_rd_check_broken_connection; + r->read_event_handler = ngx_http_block_reading; } if (ctx->entered_content_phase) { diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index b24fc992c3..82750a28b0 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) llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort != NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { + if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5274cf45cf..c46b7ccdc6 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1339,9 +1339,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort != - NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) - { + if (llcf->check_client_abort) { rc = ngx_http_lua_check_broken_connection(r, rev); if (rc == NGX_OK) { @@ -1498,14 +1496,16 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { - if (r->request_body->rest) { - ngx_http_lua_socket_handle_error(r, u, + if (llcf->check_client_abort) { + + ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); - return NGX_ERROR; - } + return NGX_ERROR; + } - } else { + /* llcf->check_client_abort == 0 */ + + if (r->request_body->rest) { ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_CLIENTABORT); return NGX_ERROR; @@ -1748,10 +1748,8 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, if (u->is_downstream) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->on_client_abort == NGX_HTTP_LUA_CLIENT_ABORT_IGNORE) { - r->read_event_handler = ngx_http_block_reading; + if (llcf->check_client_abort) { - } else { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; ev = r->connection->read; @@ -1765,6 +1763,10 @@ ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, return 2; } } + + } else { + /* llcf->check_client_abort == 0 */ + r->read_event_handler = ngx_http_block_reading; } } #endif diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 1958c4eedd..92bd2a3afb 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -35,7 +35,7 @@ __DATA__ === TEST 1: sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.sleep(1) '; @@ -63,7 +63,7 @@ client prematurely closed connection === TEST 2: sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.sleep(1) '; @@ -94,7 +94,7 @@ here in log by lua === TEST 3: sleep + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; rewrite_by_lua ' ngx.sleep(1) '; @@ -123,7 +123,7 @@ lua req cleanup === TEST 4: subrequest + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -155,7 +155,7 @@ client prematurely closed connection === TEST 5: subrequest + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; rewrite_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -186,7 +186,7 @@ bad things happen === TEST 6: subrequest + stop (proxy, ignore client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -199,7 +199,7 @@ bad things happen } location = /sleep { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.sleep(1) '; @@ -226,7 +226,7 @@ client prematurely closed connection === TEST 7: subrequest + stop (proxy, check client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -259,7 +259,7 @@ client prematurely closed connection === TEST 8: need body on + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; lua_need_request_body on; rewrite_by_lua ' ngx.sleep(1) @@ -292,7 +292,7 @@ here in log by lua === TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.req.read_body() ngx.sleep(1) @@ -325,7 +325,7 @@ here in log by lua === TEST 10: ngx.req.socket + receive() + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() sock:receive() @@ -355,7 +355,7 @@ client prematurely closed connection === TEST 11: ngx.req.socket + receive(N) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() sock:receive(5) @@ -386,7 +386,7 @@ client prematurely closed connection === TEST 12: ngx.req.socket + receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -421,7 +421,7 @@ delete thread 1)$ === TEST 13: ngx.req.socket + m * receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -455,7 +455,7 @@ client prematurely closed connection === TEST 14: ngx.req.socket + receiveuntil + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -487,7 +487,7 @@ client prematurely closed connection === TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -520,7 +520,7 @@ client prematurely closed connection === TEST 16: cosocket + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.req.discard_body() @@ -576,7 +576,7 @@ client prematurely closed connection === TEST 17: ngx.req.socket + receive n < content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() local res, err = sock:receive("*a") @@ -616,7 +616,7 @@ failed to receive: client aborted === TEST 18: ngx.req.socket + receive n == content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' local sock = ngx.req.socket() local res, err = sock:receive("*a") @@ -693,7 +693,7 @@ lua req cleanup === TEST 20: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.req.read_body() '; @@ -722,14 +722,14 @@ lua req cleanup === TEST 21: exec to lua + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.exec("/t2") '; } location = /t2 { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' ngx.sleep(1) '; @@ -759,7 +759,7 @@ lua req cleanup === TEST 22: exec to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.exec("/t2") '; @@ -795,7 +795,7 @@ delete thread 1 === TEST 23: exec (named location) to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; rewrite_by_lua ' ngx.exec("@t2") '; diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index f634982e36..49f6108c64 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -35,7 +35,7 @@ __DATA__ === TEST 1: sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.sleep(1) '; @@ -63,7 +63,7 @@ client prematurely closed connection === TEST 2: sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.sleep(1) '; @@ -94,7 +94,7 @@ here in log by lua === TEST 3: sleep + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; access_by_lua ' ngx.sleep(1) '; @@ -123,7 +123,7 @@ lua req cleanup === TEST 4: subrequest + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -155,7 +155,7 @@ client prematurely closed connection === TEST 5: subrequest + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; access_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -186,7 +186,7 @@ bad things happen === TEST 6: subrequest + stop (proxy, ignore client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -199,7 +199,7 @@ bad things happen } location = /sleep { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.sleep(1) '; @@ -226,7 +226,7 @@ client prematurely closed connection === TEST 7: subrequest + stop (proxy, check client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -259,7 +259,7 @@ client prematurely closed connection === TEST 8: need body on + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; lua_need_request_body on; access_by_lua ' ngx.sleep(1) @@ -292,7 +292,7 @@ here in log by lua === TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.req.read_body() ngx.sleep(1) @@ -325,7 +325,7 @@ here in log by lua === TEST 10: ngx.req.socket + receive() + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() sock:receive() @@ -355,7 +355,7 @@ client prematurely closed connection === TEST 11: ngx.req.socket + receive(N) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() sock:receive(5) @@ -386,7 +386,7 @@ client prematurely closed connection === TEST 12: ngx.req.socket + receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -421,7 +421,7 @@ delete thread 1)$ === TEST 13: ngx.req.socket + m * receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -455,7 +455,7 @@ client prematurely closed connection === TEST 14: ngx.req.socket + receiveuntil + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -487,7 +487,7 @@ client prematurely closed connection === TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -520,7 +520,7 @@ client prematurely closed connection === TEST 16: cosocket + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.req.discard_body() @@ -576,7 +576,7 @@ client prematurely closed connection === TEST 17: ngx.req.socket + receive n < content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() local res, err = sock:receive("*a") @@ -616,7 +616,7 @@ failed to receive: client aborted === TEST 18: ngx.req.socket + receive n == content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' local sock = ngx.req.socket() local res, err = sock:receive("*a") @@ -693,7 +693,7 @@ lua req cleanup === TEST 20: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.req.read_body() '; @@ -722,14 +722,14 @@ lua req cleanup === TEST 21: exec to lua + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.exec("/t2") '; } location = /t2 { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' ngx.sleep(1) '; @@ -759,7 +759,7 @@ lua req cleanup === TEST 22: exec to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.exec("/t2") '; @@ -795,7 +795,7 @@ delete thread 1 === TEST 23: exec (named location) to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; access_by_lua ' ngx.exec("@t2") '; diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 7b4335404d..84d66b3bf5 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -35,7 +35,7 @@ __DATA__ === TEST 1: sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.sleep(1) '; @@ -62,7 +62,7 @@ client prematurely closed connection === TEST 2: sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.sleep(1) '; @@ -93,7 +93,7 @@ here in log by lua === TEST 3: sleep + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' ngx.sleep(1) '; @@ -119,7 +119,7 @@ lua req cleanup === TEST 4: subrequest + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -151,7 +151,7 @@ client prematurely closed connection === TEST 5: subrequest + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -182,7 +182,7 @@ bad things happen === TEST 6: subrequest + stop (proxy, ignore client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -195,7 +195,7 @@ bad things happen } location = /sleep { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.sleep(1) '; @@ -222,7 +222,7 @@ client prematurely closed connection === TEST 7: subrequest + stop (proxy, check client abort) --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.location.capture("/sub") error("bad things happen") @@ -255,7 +255,7 @@ client prematurely closed connection === TEST 8: need body on + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; lua_need_request_body on; content_by_lua ' ngx.sleep(1) @@ -288,7 +288,7 @@ here in log by lua === TEST 9: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.req.read_body() ngx.sleep(1) @@ -322,7 +322,7 @@ here in log by lua === TEST 10: ngx.req.socket + receive() + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() sock:receive() @@ -352,7 +352,7 @@ client prematurely closed connection === TEST 11: ngx.req.socket + receive(N) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() sock:receive(5) @@ -383,7 +383,7 @@ client prematurely closed connection === TEST 12: ngx.req.socket + receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -415,7 +415,7 @@ delete thread 1)$ === TEST 13: ngx.req.socket + m * receive(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() sock:receive(2) @@ -449,7 +449,7 @@ client prematurely closed connection === TEST 14: ngx.req.socket + receiveuntil + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -481,7 +481,7 @@ client prematurely closed connection === TEST 15: ngx.req.socket + receiveuntil + it(n) + sleep + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() local it = sock:receiveuntil("\\n") @@ -514,7 +514,7 @@ client prematurely closed connection === TEST 16: cosocket + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.req.discard_body() @@ -570,7 +570,7 @@ client prematurely closed connection === TEST 17: ngx.req.socket + receive n < content-length + ignore --- config location /t { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' local sock = ngx.req.socket() local res, err, part = sock:receive("*a") @@ -607,7 +607,7 @@ failed to receive: client aborted: hello === TEST 18: ngx.req.socket + receive n < content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() local res, err, part = sock:receive("*a") @@ -644,7 +644,7 @@ failed to receive: client aborted: hello === TEST 19: ngx.req.socket + receive n == content-length + stop --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' local sock = ngx.req.socket() local res, err = sock:receive("*a") @@ -722,7 +722,7 @@ lua req cleanup === TEST 21: ngx.req.read_body + sleep + stop (log handler still gets called) --- config location /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.req.read_body() ngx.sleep(0.1) @@ -752,14 +752,14 @@ client prematurely closed connection === TEST 22: exec to lua + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.exec("/t2") '; } location = /t2 { - lua_on_client_abort ignore; + lua_check_client_abort off; content_by_lua ' ngx.sleep(1) '; @@ -788,7 +788,7 @@ lua req cleanup === TEST 23: exec to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.exec("/t2") '; @@ -824,7 +824,7 @@ delete thread 1 === TEST 24: exec (named location) to proxy + ignore --- config location = /t { - lua_on_client_abort stop; + lua_check_client_abort on; content_by_lua ' ngx.exec("@t2") '; @@ -871,3 +871,29 @@ qr{connect\(\) failed \(\d+: Connection refused\) while connecting to upstream} --- no_error_log [alert] + + +=== TEST 26: sleep (default off) +--- config + location /t { + content_by_lua ' + ngx.sleep(1) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: ok +delete thread 1 +lua req cleanup + +--- wait: 1 +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] + From 0b9466ac134bbbcae93298d1101fa2d30f8cbf3f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 7 Nov 2012 20:07:00 -0800 Subject: [PATCH 0155/2239] feature: ngx.exit(N) can now abort pending subrequests when N = 408 (request time out) or N = 499 (client closed request) or N = -1 (error). feature: added ngx.on_abort() for registering user Lua function callback which will get called automatically when client abortion happens. --- src/ngx_http_lua_common.h | 3 + src/ngx_http_lua_control.c | 52 ++++- src/ngx_http_lua_req_body.c | 2 +- src/ngx_http_lua_util.c | 85 +++++++- t/062-count.t | 8 +- t/101-on-abort.t | 397 ++++++++++++++++++++++++++++++++++++ t/StapThread.pm | 70 +++++-- 7 files changed, 585 insertions(+), 32 deletions(-) create mode 100644 t/101-on-abort.t diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 078dfb6b18..095397a06a 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -280,6 +280,9 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the entry coroutine */ + ngx_http_lua_co_ctx_t *on_abort_co_ctx; /* coroutine context for the + on_abort thread */ + int ctx_ref; /* reference to anchor request ctx data in lua registry */ diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 1655a6b1da..721ad9e9ef 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -5,11 +5,13 @@ #include "ngx_http_lua_control.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_coroutine.h" static int ngx_http_lua_ngx_exec(lua_State *L); static int ngx_http_lua_ngx_redirect(lua_State *L); static int ngx_http_lua_ngx_exit(lua_State *L); +static int ngx_http_lua_on_abort(lua_State *L); void @@ -32,6 +34,11 @@ ngx_http_lua_inject_control_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_exit); lua_setfield(L, -2, "exit"); + + /* ngx.on_abort */ + + lua_pushcfunction(L, ngx_http_lua_on_abort); + lua_setfield(L, -2, "on_abort"); } @@ -304,10 +311,16 @@ ngx_http_lua_ngx_exit(lua_State *L) | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); - ngx_http_lua_check_if_abortable(L, ctx); - rc = (ngx_int_t) luaL_checkinteger(L, 1); + if (ctx->no_abort + && rc != NGX_ERROR + && rc != NGX_HTTP_REQUEST_TIME_OUT + && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST) + { + return luaL_error(L, "attempt to abort with pending subrequests"); + } + if (rc >= NGX_HTTP_SPECIAL_RESPONSE && ctx->headers_sent) { if (rc != (ngx_int_t) r->headers_out.status) { @@ -329,3 +342,38 @@ ngx_http_lua_ngx_exit(lua_State *L) return lua_yield(L, 0); } + +static int +ngx_http_lua_on_abort(lua_State *L) +{ + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_co_ctx_t *coctx = NULL; + ngx_http_lua_loc_conf_t *llcf; + + ngx_http_lua_coroutine_create_helper(L, &r, &ctx, &coctx); + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); + if (!llcf->check_client_abort) { + lua_pushnil(L); + lua_pushliteral(L, "lua_check_client_abort is off"); + return 2; + } + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, -3); + coctx->co_ref = luaL_ref(L, -2); + lua_pop(L, 1); + + coctx->is_uthread = 1; + ctx->uthreads++; + ctx->on_abort_co_ctx = coctx; + + coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; + coctx->parent_co_ctx = ctx->cur_co_ctx; + + lua_pushinteger(L, 1); + return 1; +} + diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index c689dcbaa5..f0c20f2cb7 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -149,7 +149,7 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua req body post read"); + "lua req body post read"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index acb7b83bfe..a78cb67647 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -39,6 +39,7 @@ #include "ngx_http_lua_phase.h" #include "ngx_http_lua_probe.h" #include "ngx_http_lua_uthread.h" +#include "ngx_http_lua_contentby.h" #if 1 @@ -86,6 +87,7 @@ static ngx_int_t ngx_http_lua_post_zombie_thread(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *parent, ngx_http_lua_co_ctx_t *thread); 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); #ifndef LUA_PATH_SEP @@ -701,7 +703,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 */, 84 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 85 /* nrec */); /* ngx.* */ ngx_http_lua_inject_arg_api(L); @@ -2984,7 +2986,6 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) } ev->eof = 1; - c->error = 1; if (ev->kq_errno) { ev->error = 1; @@ -3041,7 +3042,6 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) } ev->eof = 1; - c->error = 1; ngx_log_error(NGX_LOG_INFO, ev->log, err, "client prematurely closed connection"); @@ -3053,7 +3053,8 @@ ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev) void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) { - ngx_int_t rc; + ngx_int_t rc; + ngx_http_lua_ctx_t *ctx; rc = ngx_http_lua_check_broken_connection(r, r->connection->read); @@ -3063,8 +3064,80 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) /* rc == NGX_ERROR || rc > NGX_OK */ - ngx_http_lua_request_cleanup(r); - ngx_http_finalize_request(r, rc); + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return; + } + + if (ctx->on_abort_co_ctx == NULL) { + r->connection->error = 1; + ngx_http_lua_request_cleanup(r); + ngx_http_finalize_request(r, rc); + return; + } + + /* ctx->on_abort_co_ctx != NULL */ + + ctx->resume_handler = ngx_http_lua_on_abort_resume; + ctx->cur_co_ctx = ctx->on_abort_co_ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua waking up the on_abort callback thread"); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; + } + + r->write_event_handler(r); +} + + +static ngx_int_t +ngx_http_lua_on_abort_resume(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_lua_ctx_t *ctx; + ngx_http_lua_main_conf_t *lmcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_http_lua_wev_handler; + + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua resuming the on_abort callback thread"); + +#if 0 + ngx_http_lua_probe_info("tcp resume"); +#endif + + c = r->connection; + + rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_http_lua_run_posted_threads(c, lmcf->lua, r, ctx); + } + + if (rc == NGX_DONE) { + ngx_http_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); + return NGX_DONE; + } + + return rc; } diff --git a/t/062-count.t b/t/062-count.t index 848c7f2c6d..53a64c9c4c 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -35,7 +35,7 @@ __DATA__ --- request GET /test --- response_body -ngx: 84 +ngx: 85 --- no_error_log [error] @@ -56,7 +56,7 @@ ngx: 84 --- request GET /test --- response_body -84 +85 --- no_error_log [error] @@ -84,7 +84,7 @@ GET /test --- request GET /test --- response_body -n = 84 +n = 85 --- no_error_log [error] @@ -301,5 +301,5 @@ GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- error_log -ngx. entry count: 84 +ngx. entry count: 85 diff --git a/t/101-on-abort.t b/t/101-on-abort.t new file mode 100644 index 0000000000..2995bde557 --- /dev/null +++ b/t/101-on-abort.t @@ -0,0 +1,397 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 5); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ignore the client abort event in the user callback +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +terminate 1: ok +delete thread 2 +delete thread 1 +lua req cleanup + +--- timeout: 0.1 +--- wait: 0.5 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 2: abort in the user callback +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.5) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 3: ngx.exit(499) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 4: ngx.exit(408) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(408) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 5: ngx.exit(-1) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(-1) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 6: ngx.exit(0) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(0) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + ngx.log(ngx.ERR, "main handler done") + '; + } + + location = /sleep { + echo_sleep 0.5; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: fail +terminate 1: ok +delete thread 2 +delete thread 1 +lua req cleanup + +--- timeout: 0.1 +--- wait: 0.4 +--- ignore_response +--- 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 +main handler done + + + +=== TEST 7: accessing cosocket in callback +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to redis: ", err) + ngx.exit(499) + end + local bytes, err = sock:send("flushall\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + ngx.exit(499) + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive: ", err) + ngx.exit(499) + end + ngx.log(ngx.NOTICE, "callback done: ", res) + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.1 +--- wait: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called +callback done: +OK + + + +=== TEST 8: ignore the client abort event in the user callback +--- config + location /t { + lua_check_client_abort off; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: fail +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- wait: 0.5 +--- ignore_response +--- no_error_log +client prematurely closed connection +on abort called +main handler done + +--- error_log +cannot set on_abort: lua_check_client_abort is off + diff --git a/t/StapThread.pm b/t/StapThread.pm index 1283854062..791ea28ec2 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -6,6 +6,7 @@ use warnings; our $GCScript = <<'_EOC_'; global ids, cur global in_req = 0 +global alive_reqs function gen_id(k) { if (ids[k]) return ids[k] @@ -13,16 +14,30 @@ function gen_id(k) { return cur } -F(ngx_http_init_request) { - in_req++ - if (in_req == 1) { - delete ids - cur = 0 +F(ngx_http_handler) { + if (!alive_reqs[$r] && $r == $r->main) { + in_req++ + alive_reqs[$r] = 1 + + if (in_req == 1) { + delete ids + cur = 0 + } } } F(ngx_http_free_request) { - in_req-- + if (alive_reqs[$r]) { + in_req-- + delete alive_reqs[$r] + } +} + +F(ngx_http_terminate_request) { + if (alive_reqs[$r]) { + in_req-- + delete alive_reqs[$r] + } } M(http-lua-user-thread-spawn) { @@ -55,6 +70,7 @@ global ids, cur global timers global in_req = 0 global co_status +global alive_reqs function gen_id(k) { if (ids[k]) return ids[k] @@ -62,24 +78,38 @@ function gen_id(k) { return cur } -F(ngx_http_init_request) { - in_req++ +F(ngx_http_handler) { + if (!alive_reqs[$r] && $r == $r->main) { + in_req++ + alive_reqs[$r] = 1 - printf("in req: %d\n", in_req) + printf("in req: %d\n", in_req) - if (in_req == 1) { - delete ids - cur = 0 - co_status[0] = "running" - co_status[1] = "suspended" - co_status[2] = "normal" - co_status[3] = "dead" + if (in_req == 1) { + delete ids + cur = 0 + co_status[0] = "running" + co_status[1] = "suspended" + co_status[2] = "normal" + co_status[3] = "dead" + } } } F(ngx_http_free_request) { - in_req-- - println("free request") + if (alive_reqs[$r]) { + in_req-- + println("free request") + delete alive_reqs[$r] + } +} + +F(ngx_http_terminate_request) { + if (alive_reqs[$r]) { + in_req-- + println("terminate request") + delete alive_reqs[$r] + } } F(ngx_http_lua_post_thread) { @@ -171,7 +201,9 @@ F(ngx_http_lua_run_posted_threads) { F(ngx_http_finalize_request) { printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); - #print_ubacktrace() + #if ($rc == -1) { + #print_ubacktrace() + #} } M(http-lua-user-coroutine-create) { From b3a7787023985f68d369ae5ccab1bfa7167d5b94 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 8 Nov 2012 12:20:39 -0800 Subject: [PATCH 0156/2239] bugfix: request might hang when a callback function is registered via ngx.on_abort() and there was no client abort event at all. also ensured that the on_abort callback will not get called when the request is already done. --- src/ngx_http_lua_control.c | 1 - src/ngx_http_lua_util.c | 44 +++++++-- t/101-on-abort.t | 184 ++++++++++++++++++++++++++++++++++++- 3 files changed, 221 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 721ad9e9ef..5ecd1f3452 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -367,7 +367,6 @@ ngx_http_lua_on_abort(lua_State *L) lua_pop(L, 1); coctx->is_uthread = 1; - ctx->uthreads++; ctx->on_abort_co_ctx = coctx; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a78cb67647..2363b3edd6 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -327,13 +327,37 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, ngx_http_lua_co_ctx_t *entry_coctx; ngx_http_lua_co_ctx_t *cc; - if (ctx->uthreads && ctx->user_co_ctx) { - /* release all pending user threads */ - + cc = ctx->on_abort_co_ctx; + if (cc) { lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); inited = 1; + if (cc->co_ref != LUA_NOREF) { + ngx_http_lua_probe_thread_delete(r, cc->co, ctx); + + luaL_unref(L, -1, cc->co_ref); + cc->co_ref = LUA_NOREF; + + if (cc->co_status != NGX_HTTP_LUA_CO_SUSPENDED) { + ctx->uthreads--; + } + + cc->co_status = NGX_HTTP_LUA_CO_DEAD; + } + + ctx->on_abort_co_ctx = NULL; + } + + if (ctx->uthreads && ctx->user_co_ctx) { + /* release all pending user threads */ + + if (!inited) { + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + inited = 1; + } + cc = ctx->user_co_ctx->elts; for (i = 0; i < ctx->user_co_ctx->nelts; i++) { @@ -833,6 +857,8 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->entered_access_phase = 0; ctx->entered_content_phase = 0; + ctx->on_abort_co_ctx = NULL; + ctx->exit_code = 0; ctx->exited = 0; ctx->resume_handler = ngx_http_lua_wev_handler; @@ -3056,6 +3082,10 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) ngx_int_t rc; ngx_http_lua_ctx_t *ctx; + if (r->done) { + return; + } + rc = ngx_http_lua_check_broken_connection(r, r->connection->read); if (rc == NGX_OK) { @@ -3069,16 +3099,18 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) return; } - if (ctx->on_abort_co_ctx == NULL) { + if (ctx->on_abort_co_ctx == NULL + || ctx->on_abort_co_ctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) + { r->connection->error = 1; ngx_http_lua_request_cleanup(r); ngx_http_finalize_request(r, rc); return; } - /* ctx->on_abort_co_ctx != NULL */ - + ctx->uthreads++; ctx->resume_handler = ngx_http_lua_on_abort_resume; + ctx->on_abort_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ctx->cur_co_ctx = ctx->on_abort_co_ctx; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 2995bde557..575a54895a 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 5); +plan tests => repeat_each() * (blocks() * 4 + 14); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -90,6 +90,7 @@ main handler done end ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") '; } --- request @@ -109,6 +110,7 @@ delete thread 1 --- ignore_response --- no_error_log [error] +main handler done --- error_log client prematurely closed connection on abort called @@ -395,3 +397,183 @@ main handler done --- error_log cannot set on_abort: lua_check_client_abort is off + + +=== TEST 9: regsiter on_abort callback but no client abortion +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.say("done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +lua req cleanup +delete thread 2 + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 10: ignore the client abort event in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- timeout: 0.1 +--- wait: 0.5 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 11: abort in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.5) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 3 + +--- timeout: 0.1 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 12: regsiter on_abort callback but no client abortion (uthread) +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +terminate 3: ok +delete thread 3 +lua req cleanup +delete thread 2 + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + From 1d5b18a81dee56446861198ea5c111ce11a07195 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 8 Nov 2012 15:55:29 -0800 Subject: [PATCH 0157/2239] bugfix: calling ngx.on_abort() twice in a single handler will result in memory leaks; now it returns an error upon subsequent calls. --- src/ngx_http_lua_control.c | 22 ++++++++++++++- src/ngx_http_lua_coroutine.c | 43 +++++++++++++---------------- src/ngx_http_lua_coroutine.h | 4 +-- src/ngx_http_lua_uthread.c | 16 ++++++++++- t/101-on-abort.t | 52 ++++++++++++++++++++++++++++++++++-- 5 files changed, 106 insertions(+), 31 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 5ecd1f3452..62e144bc1a 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -351,7 +351,25 @@ ngx_http_lua_on_abort(lua_State *L) ngx_http_lua_co_ctx_t *coctx = NULL; ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_coroutine_create_helper(L, &r, &ctx, &coctx); + 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 found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no request ctx found"); + } + + if (ctx->on_abort_co_ctx) { + lua_pushnil(L); + lua_pushliteral(L, "duplicate call"); + return 2; + } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (!llcf->check_client_abort) { @@ -360,6 +378,8 @@ ngx_http_lua_on_abort(lua_State *L) return 2; } + ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -3); diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index a30c92cc70..5ab38e7803 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -32,23 +32,8 @@ static const char * static int ngx_http_lua_coroutine_create(lua_State *L) { - return ngx_http_lua_coroutine_create_helper(L, NULL, NULL, NULL); -} - - -int -ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, - ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx) -{ - lua_State *mt; /* the main thread */ - lua_State *co; /* new coroutine to be created */ - ngx_http_request_t *r; - ngx_http_lua_main_conf_t *lmcf; - ngx_http_lua_ctx_t *ctx; - ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ - - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); @@ -64,6 +49,22 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, return luaL_error(L, "no request ctx found"); } + return ngx_http_lua_coroutine_create_helper(L, r, ctx, NULL); +} + + +int +ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx) +{ + lua_State *mt; /* the main thread */ + lua_State *co; /* new coroutine to be created */ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ + + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); @@ -101,14 +102,6 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, *pcoctx = coctx; } - if (pctx) { - *pctx = ctx; - } - - if (pr) { - *pr = r; - } - return 1; /* return new coroutine to Lua */ } diff --git a/src/ngx_http_lua_coroutine.h b/src/ngx_http_lua_coroutine.h index 49a5f5ebf3..d2be426d17 100644 --- a/src/ngx_http_lua_coroutine.h +++ b/src/ngx_http_lua_coroutine.h @@ -9,8 +9,8 @@ void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L); -int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t **pr, - ngx_http_lua_ctx_t **pctx, ngx_http_lua_co_ctx_t **pcoctx); +int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx); #endif /* NGX_HTTP_LUA_COROUTINE_H */ diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 425533248b..9c8cfa8091 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -46,7 +46,21 @@ ngx_http_lua_uthread_spawn(lua_State *L) n = lua_gettop(L); - ngx_http_lua_coroutine_create_helper(L, &r, &ctx, &coctx); + 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 found"); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no request ctx found"); + } + + ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); /* anchor the newly created coroutine into the Lua registry */ diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 575a54895a..6fee05bc8e 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -358,7 +358,7 @@ callback done: +OK -=== TEST 8: ignore the client abort event in the user callback +=== TEST 8: ignore the client abort event in the user callback (no check) --- config location /t { lua_check_client_abort off; @@ -381,7 +381,6 @@ GET /t --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -create 2 in 1 terminate 1: fail lua req cleanup delete thread 1 @@ -577,3 +576,52 @@ client prematurely closed connection on abort called main handler done + + +=== TEST 13: regsiter on_abort callback multiple times +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("1: cannot set on_abort: " .. err) + return + end + + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("2: cannot set on_abort: " .. err) + return + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +lua req cleanup +delete thread 2 + +--- response_body +2: cannot set on_abort: duplicate call + +--- no_error_log +[error] + From 75be85db6397ab04640332526b691ce4b6a1c7c3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 8 Nov 2012 16:24:00 -0800 Subject: [PATCH 0158/2239] made the tests less possible to fail in slow testing modes. --- t/023-rewrite/client-abort.t | 29 ++++++++++++++------------- t/024-access/client-abort.t | 30 +++++++++++++++------------- t/100-client-abort.t | 32 +++++++++++++++--------------- t/101-on-abort.t | 38 ++++++++++++++++++------------------ 4 files changed, 66 insertions(+), 63 deletions(-) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 92bd2a3afb..6b39cc619d 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -51,7 +51,7 @@ lua req cleanup delete thread 1 --- wait: 0.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -81,7 +81,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -113,7 +113,7 @@ delete thread 2 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -143,7 +143,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -176,7 +176,7 @@ lua req cleanup delete thread 1 --- wait: 1.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- error_log bad things happen @@ -214,7 +214,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -247,7 +247,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -279,7 +279,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -312,7 +312,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -604,7 +604,7 @@ terminate 2: ok delete thread 2 lua req cleanup ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -627,6 +627,7 @@ failed to receive: client aborted ngx.sleep(1) error("bad") '; + content_by_lua return; } --- raw_request eval "POST /t HTTP/1.0\r @@ -643,7 +644,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -748,7 +749,7 @@ delete thread 2 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -784,7 +785,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -820,7 +821,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 49f6108c64..02560302f0 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -51,7 +51,7 @@ lua req cleanup delete thread 1 --- wait: 0.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -81,7 +81,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -113,7 +113,7 @@ delete thread 2 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -143,7 +143,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -176,7 +176,7 @@ lua req cleanup delete thread 1 --- wait: 1.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- error_log bad things happen @@ -214,7 +214,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -247,7 +247,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -279,7 +279,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -312,7 +312,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -604,7 +604,7 @@ terminate 2: ok delete thread 2 lua req cleanup ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -627,6 +627,8 @@ failed to receive: client aborted ngx.sleep(1) error("bad") '; + + content_by_lua return; } --- raw_request eval "POST /t HTTP/1.0\r @@ -643,7 +645,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -748,7 +750,7 @@ delete thread 2 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -784,7 +786,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -820,7 +822,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 84d66b3bf5..f52d5fe4b5 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -50,7 +50,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -80,7 +80,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -109,7 +109,7 @@ delete thread 1 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -139,7 +139,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -172,7 +172,7 @@ lua req cleanup delete thread 1 --- wait: 1.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- error_log bad things happen @@ -210,7 +210,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -243,7 +243,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -275,7 +275,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -309,7 +309,7 @@ lua req cleanup delete thread 1 --- wait: 0.1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -502,7 +502,7 @@ lua check broken conn lua req cleanup delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -595,7 +595,7 @@ terminate 1: ok delete thread 1 lua req cleanup ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -632,7 +632,7 @@ terminate 1: ok delete thread 1 lua req cleanup ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -778,7 +778,7 @@ delete thread 2 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -813,7 +813,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -849,7 +849,7 @@ lua req cleanup delete thread 1 --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -891,7 +891,7 @@ delete thread 1 lua req cleanup --- wait: 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 6fee05bc8e..8e9d6bae97 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -45,7 +45,7 @@ __DATA__ error("cannot set on_abort: " .. err) end - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; } @@ -63,8 +63,8 @@ delete thread 2 delete thread 1 lua req cleanup ---- timeout: 0.1 ---- wait: 0.5 +--- timeout: 0.2 +--- wait: 0.7 --- ignore_response --- no_error_log [error] @@ -89,7 +89,7 @@ main handler done error("cannot set on_abort: " .. err) end - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; } @@ -106,7 +106,7 @@ lua req cleanup delete thread 2 delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -151,7 +151,7 @@ lua req cleanup delete thread 2 delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -195,7 +195,7 @@ lua req cleanup delete thread 2 delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -239,7 +239,7 @@ lua req cleanup delete thread 2 delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] @@ -269,7 +269,7 @@ on abort called } location = /sleep { - echo_sleep 0.5; + echo_sleep 0.7; } --- request GET /t @@ -285,7 +285,7 @@ delete thread 2 delete thread 1 lua req cleanup ---- timeout: 0.1 +--- timeout: 0.2 --- wait: 0.4 --- ignore_response --- error_log @@ -328,7 +328,7 @@ main handler done error("cannot set on_abort: " .. err) end - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; } @@ -345,7 +345,7 @@ lua req cleanup delete thread 2 delete thread 1 ---- timeout: 0.1 +--- timeout: 0.2 --- wait: 0.2 --- ignore_response --- no_error_log @@ -371,7 +371,7 @@ callback done: +OK error("cannot set on_abort: " .. err) end - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") '; } @@ -386,7 +386,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 ---- wait: 0.5 +--- wait: 0.7 --- ignore_response --- no_error_log client prematurely closed connection @@ -450,7 +450,7 @@ main handler done end ngx.thread.spawn(function () - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") end) '; @@ -473,8 +473,8 @@ terminate 3: ok delete thread 3 lua req cleanup ---- timeout: 0.1 ---- wait: 0.5 +--- timeout: 0.2 +--- wait: 0.7 --- ignore_response --- no_error_log [error] @@ -500,7 +500,7 @@ main handler done end ngx.thread.spawn(function () - ngx.sleep(0.5) + ngx.sleep(0.7) ngx.log(ngx.NOTICE, "main handler done") end) '; @@ -522,7 +522,7 @@ lua req cleanup delete thread 2 delete thread 3 ---- timeout: 0.1 +--- timeout: 0.2 --- ignore_response --- no_error_log [error] From 0990bdef77043315879ca04fb892dafc7b08f6ea Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 8 Nov 2012 16:39:20 -0800 Subject: [PATCH 0159/2239] ported the tests for ngx.on_abort() to access_by_lua and rewrite_by_lua. --- t/023-rewrite/on-abort.t | 652 +++++++++++++++++++++++++++++++++++++++ t/024-access/on-abort.t | 652 +++++++++++++++++++++++++++++++++++++++ t/101-on-abort.t | 2 +- 3 files changed, 1305 insertions(+), 1 deletion(-) create mode 100644 t/023-rewrite/on-abort.t create mode 100644 t/024-access/on-abort.t diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t new file mode 100644 index 0000000000..ca34d0d010 --- /dev/null +++ b/t/023-rewrite/on-abort.t @@ -0,0 +1,652 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 14); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ignore the client abort event in the user callback +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +terminate 1: ok +delete thread 2 +delete thread 1 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 2: abort in the user callback +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 3: ngx.exit(499) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 4: ngx.exit(408) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(408) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 5: ngx.exit(-1) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(-1) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 6: ngx.exit(0) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(0) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + ngx.log(ngx.ERR, "main handler done") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.7; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: fail +terminate 1: ok +delete thread 2 +delete thread 1 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.5 +--- ignore_response +--- 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 +main handler done + + + +=== TEST 7: accessing cosocket in callback +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to redis: ", err) + ngx.exit(499) + end + local bytes, err = sock:send("flushall\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + ngx.exit(499) + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive: ", err) + ngx.exit(499) + end + ngx.log(ngx.NOTICE, "callback done: ", res) + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- wait: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called +callback done: +OK + + + +=== TEST 8: ignore the client abort event in the user callback (no check) +--- config + location /t { + lua_check_client_abort off; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +client prematurely closed connection +on abort called +main handler done + +--- error_log +cannot set on_abort: lua_check_client_abort is off + + + +=== TEST 9: regsiter on_abort callback but no client abortion +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.say("done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +delete thread 2 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 10: ignore the client abort event in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 11: abort in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 3 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 12: regsiter on_abort callback but no client abortion (uthread) +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +terminate 3: ok +delete thread 3 +delete thread 2 +terminate 4: ok +delete thread 4 +lua req cleanup + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 13: regsiter on_abort callback multiple times +--- config + location /t { + lua_check_client_abort on; + rewrite_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("1: cannot set on_abort: " .. err) + return + end + + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("2: cannot set on_abort: " .. err) + return + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +delete thread 2 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- response_body +2: cannot set on_abort: duplicate call + +--- no_error_log +[error] + diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t new file mode 100644 index 0000000000..16af3b0540 --- /dev/null +++ b/t/024-access/on-abort.t @@ -0,0 +1,652 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; +use t::StapThread; + +our $GCScript = <<_EOC_; +$t::StapThread::GCScript + +F(ngx_http_lua_check_broken_connection) { + println("lua check broken conn") +} + +F(ngx_http_lua_request_cleanup) { + println("lua req cleanup") +} +_EOC_ + +our $StapScript = $t::StapThread::StapScript; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 4 + 14); + +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; +$ENV{TEST_NGINX_REDIS_PORT} ||= '6379'; + +#no_shuffle(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ignore the client abort event in the user callback +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +terminate 1: ok +delete thread 2 +delete thread 1 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 2: abort in the user callback +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 3: ngx.exit(499) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 4: ngx.exit(408) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(408) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 5: ngx.exit(-1) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(-1) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 1; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 6: ngx.exit(0) with pending subrequest +--- config + location = /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(0) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.location.capture("/sleep") + ngx.log(ngx.ERR, "main handler done") + '; + content_by_lua return; + } + + location = /sleep { + echo_sleep 0.7; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: fail +terminate 1: ok +delete thread 2 +delete thread 1 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.5 +--- ignore_response +--- 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 +main handler done + + + +=== TEST 7: accessing cosocket in callback +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT) + if not ok then + ngx.log(ngx.ERR, "failed to connect to redis: ", err) + ngx.exit(499) + end + local bytes, err = sock:send("flushall\\r\\n") + if not bytes then + ngx.log(ngx.ERR, "failed to send query: ", err) + ngx.exit(499) + end + + local res, err = sock:receive() + if not res then + ngx.log(ngx.ERR, "failed to receive: ", err) + ngx.exit(499) + end + ngx.log(ngx.NOTICE, "callback done: ", res) + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- wait: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called +callback done: +OK + + + +=== TEST 8: ignore the client abort event in the user callback (no check) +--- config + location /t { + lua_check_client_abort off; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +terminate 1: fail +lua req cleanup +delete thread 1 + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +client prematurely closed connection +on abort called +main handler done + +--- error_log +cannot set on_abort: lua_check_client_abort is off + + + +=== TEST 9: regsiter on_abort callback but no client abortion +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.say("done") + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +delete thread 2 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 10: ignore the client abort event in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +lua req cleanup + +--- timeout: 0.2 +--- wait: 0.7 +--- ignore_response +--- no_error_log +[error] +--- error_log +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 11: abort in the user callback (uthread) +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 3 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 12: regsiter on_abort callback but no client abortion (uthread) +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +terminate 3: ok +delete thread 3 +delete thread 2 +terminate 4: ok +delete thread 4 +lua req cleanup + +--- response_body +done +--- no_error_log +[error] +client prematurely closed connection +on abort called +main handler done + + + +=== TEST 13: regsiter on_abort callback multiple times +--- config + location /t { + lua_check_client_abort on; + access_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("1: cannot set on_abort: " .. err) + return + end + + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + end) + + if not ok then + ngx.say("2: cannot set on_abort: " .. err) + return + end + + ngx.thread.spawn(function () + ngx.sleep(0.1) + ngx.say("done") + end) + '; + content_by_lua return; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +terminate 1: ok +delete thread 1 +delete thread 2 +terminate 3: ok +delete thread 3 +lua req cleanup + +--- response_body +2: cannot set on_abort: duplicate call + +--- no_error_log +[error] + diff --git a/t/101-on-abort.t b/t/101-on-abort.t index 8e9d6bae97..cd20616953 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -286,7 +286,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 ---- wait: 0.4 +--- wait: 0.5 --- ignore_response --- error_log client prematurely closed connection From e06f7e3a24d28d12fc72d7d28e08438a072251ac Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 8 Nov 2012 20:58:28 -0800 Subject: [PATCH 0160/2239] polished the test cases that could expectedly fail. --- t/023-rewrite/on-abort.t | 20 ++++++++++---------- t/024-access/on-abort.t | 20 ++++++++++---------- t/101-on-abort.t | 16 +++++++--------- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index ca34d0d010..9ff61b7582 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 14); +plan tests => repeat_each() * (blocks() * 4 + 15); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -67,7 +67,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 ---- wait: 0.7 +--- wait: 0.5 --- ignore_response --- no_error_log [error] @@ -379,7 +379,8 @@ callback done: +OK end) if not ok then - error("cannot set on_abort: " .. err) + ngx.say("cannot set on_abort: ", err) + return end ngx.sleep(0.7) @@ -393,21 +394,20 @@ GET /t --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -terminate 1: fail -lua req cleanup +terminate 1: ok delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup --- timeout: 0.2 ---- wait: 0.7 ---- ignore_response +--- response_body +cannot set on_abort: lua_check_client_abort is off --- no_error_log client prematurely closed connection on abort called main handler done ---- error_log -cannot set on_abort: lua_check_client_abort is off - === TEST 9: regsiter on_abort callback but no client abortion diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 16af3b0540..a7630063ff 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 14); +plan tests => repeat_each() * (blocks() * 4 + 15); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -67,7 +67,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 ---- wait: 0.7 +--- wait: 0.5 --- ignore_response --- no_error_log [error] @@ -379,7 +379,8 @@ callback done: +OK end) if not ok then - error("cannot set on_abort: " .. err) + ngx.say("cannot set on_abort: ", err) + return end ngx.sleep(0.7) @@ -393,21 +394,20 @@ GET /t --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -terminate 1: fail -lua req cleanup +terminate 1: ok delete thread 1 +terminate 2: ok +delete thread 2 +lua req cleanup --- timeout: 0.2 ---- wait: 0.7 ---- ignore_response +--- response_body +cannot set on_abort: lua_check_client_abort is off --- no_error_log client prematurely closed connection on abort called main handler done ---- error_log -cannot set on_abort: lua_check_client_abort is off - === TEST 9: regsiter on_abort callback but no client abortion diff --git a/t/101-on-abort.t b/t/101-on-abort.t index cd20616953..f710c919e9 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 14); +plan tests => repeat_each() * (blocks() * 4 + 15); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -368,7 +368,8 @@ callback done: +OK end) if not ok then - error("cannot set on_abort: " .. err) + ngx.say("cannot set on_abort: ", err) + return end ngx.sleep(0.7) @@ -381,21 +382,18 @@ GET /t --- stap2 eval: $::StapScript --- stap eval: $::GCScript --- stap_out -terminate 1: fail -lua req cleanup +terminate 1: ok delete thread 1 +lua req cleanup --- timeout: 0.2 ---- wait: 0.7 ---- ignore_response +--- response_body +cannot set on_abort: lua_check_client_abort is off --- no_error_log client prematurely closed connection on abort called main handler done ---- error_log -cannot set on_abort: lua_check_client_abort is off - === TEST 9: regsiter on_abort callback but no client abortion From fc4391e07256fff7e88b884ab304008c29b16eee Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 11 Nov 2012 12:35:00 -0800 Subject: [PATCH 0161/2239] documented lua_check_client_abort and ngx.on_abort; also bumped version to 0.7.4. --- README | 93 ++++++++++++++++++++++++++++++++++++++++-- README.markdown | 69 ++++++++++++++++++++++++++++++- doc/HttpLuaModule.wiki | 67 +++++++++++++++++++++++++++++- 3 files changed, 224 insertions(+), 5 deletions(-) diff --git a/README b/README index ee083713c6..67dcc2411b 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.3 - () released on 30 - October 2012. + This document describes ngx_lua v0.7.4 + () released on 11 + November 2012. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -1297,6 +1297,46 @@ Directives This directive was first introduced in the "v0.5.0rc32" release. + lua_check_client_abort + syntax: *lua_check_client_abort on|off* + + default: *lua_check_client_abort off* + + context: *http, server, location, location-if* + + This directive controls whether to check for premature client connection + abortion. + + When this directive is turned on, the ngx_lua module will monitor the + premature connection close event on the downstream connections. And when + there is such an event, it will call the user Lua function callback + (registered by ngx.on_abort) or just stop and clean up all the Lua + "light threads" running in the current request's request handler when + there is no user callback function registered. + + When TCP keepalive is disabled, it is relying on the client side to + close the socket gracefully (by sending a "FIN" packet or something like + that). For (soft) real-time web applications, it is highly recommended + to configure the TCP keepalive + () support in + your system's TCP stack implementation in order to detect "half-open" + TCP connections in time. + + For example, on Linux, you can configure the standard listen directive + in your "nginx.conf" file like this: + + listen 80 so_keepalive=2s:2s:8; + + On FreeBSD, you can only tune the system-wide configuration for TCP + keepalive, for example: + + # sysctl net.inet.tcp.keepintvl=2000 + # sysctl net.inet.tcp.keepidle=2000 + + This directive was first introduced in the "v0.7.4" release. + + See also ngx.on_abort. + Nginx API for Lua Introduction The various *_by_lua and *_by_lua_file configuration directives serve as @@ -4980,6 +5020,53 @@ Nginx API for Lua This API was first enabled in the "v0.7.0" release. + ngx.on_abort + syntax: *ok, err = ngx.on_abort(callback)* + + context: *rewrite_by_lua*, access_by_lua*, content_by_lua** + + Registers a user Lua function as the callback which gets called + automatically when the client closes the (downstream) connection + prematurely. + + Returns 1 if the callback is registered successfully or returns "nil" + and a string describing the error otherwise. + + All the Nginx API for Lua can be used in the callback function because + the function is run in a special "light thread", just as those "light + threads" created by ngx.thread.spawn. + + The callback function can decide what to do with the client abortion + event all by itself. For example, it can simply ignore the event by + doing nothing and the current Lua request handler will continue + executing without interruptions. And the callback function can also + decide to terminate everything by calling ngx.exit, for example, + + local function my_cleanup() + -- custom cleanup work goes here, like cancelling a pending DB transaction + + -- now abort all the "light threads" running in the current request handler + ngx.exit(499) + end + + local ok, err = ngx.on_abort(my_cleanup) + if not ok then + ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) + ngx.exit(500) + end + + When lua_check_client_abort is set to "off" (which is the default), then + this function call will always return the error message + "lua_check_client_abort is off". + + According to the current implementation, this function can only be + called once in a single request handler; subsequent calls will return + the error message "duplicate call". + + This API was first introduced in the "v0.7.4" release. + + See also lua_check_client_abort. + ndk.set_var.DIRECTIVE syntax: *res = ndk.set_var.DIRECTIVE_NAME* diff --git a/README.markdown b/README.markdown index 50303a0dee..1c9152e88b 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.3](https://github.com/chaoslawful/lua-nginx-module/tags) released on 30 October 2012. +This document describes ngx_lua [v0.7.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 11 November 2012. Synopsis ======== @@ -1151,6 +1151,36 @@ Controls whether to transform underscores (`_`) in the response header names spe This directive was first introduced in the `v0.5.0rc32` release. +lua_check_client_abort +---------------------- + +**syntax:** *lua_check_client_abort on|off* + +**default:** *lua_check_client_abort off* + +**context:** *http, server, location, location-if* + +This directive controls whether to check for premature client connection abortion. + +When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](http://wiki.nginx.org/HttpLuaModule#ngx.on_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. + +When TCP keepalive is disabled, it is relying on the client side to close the socket gracefully (by sending a `FIN` packet or something like that). For (soft) real-time web applications, it is highly recommended to configure the [TCP keepalive](http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) support in your system's TCP stack implementation in order to detect "half-open" TCP connections in time. + +For example, on Linux, you can configure the standard [listen](http://wiki.nginx.org/HttpCoreModule#listen) directive in your `nginx.conf` file like this: + + + listen 80 so_keepalive=2s:2s:8; + + +On FreeBSD, you can only tune the system-wide configuration for TCP keepalive, for example: + + # sysctl net.inet.tcp.keepintvl=2000 + # sysctl net.inet.tcp.keepidle=2000 + +This directive was first introduced in the `v0.7.4` release. + +See also [ngx.on_abort](http://wiki.nginx.org/HttpLuaModule#ngx.on_abort). + Nginx API for Lua ================= Introduction @@ -4451,6 +4481,43 @@ And it will generate the following output: This API was first enabled in the `v0.7.0` release. +ngx.on_abort +------------ +**syntax:** *ok, err = ngx.on_abort(callback)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** + +Registers a user Lua function as the callback which gets called automatically when the client closes the (downstream) connection prematurely. + +Returns `1` if the callback is registered successfully or returns `nil` and a string describing the error otherwise. + +All the [Nginx API for Lua](http://wiki.nginx.org/HttpLuaModule#Nginx_API_for_Lua) can be used in the callback function because the function is run in a special "light thread", just as those "light threads" created by [ngx.thread.spawn](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn). + +The callback function can decide what to do with the client abortion event all by itself. For example, it can simply ignore the event by doing nothing and the current Lua request handler will continue executing without interruptions. And the callback function can also decide to terminate everything by calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit), for example, + + + local function my_cleanup() + -- custom cleanup work goes here, like cancelling a pending DB transaction + + -- now abort all the "light threads" running in the current request handler + ngx.exit(499) + end + + local ok, err = ngx.on_abort(my_cleanup) + if not ok then + ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) + ngx.exit(500) + end + + +When [lua_check_client_abort](http://wiki.nginx.org/HttpLuaModule#lua_check_client_abort) is set to `off` (which is the default), then this function call will always return the error message "lua_check_client_abort is off". + +According to the current implementation, this function can only be called once in a single request handler; subsequent calls will return the error message "duplicate call". + +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). + ndk.set_var.DIRECTIVE --------------------- **syntax:** *res = ndk.set_var.DIRECTIVE_NAME* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 2d63f9e2c9..9a0223e2d1 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.3] released on 30 October 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.4] released on 11 November 2012. = Synopsis = @@ -1107,6 +1107,35 @@ Controls whether to transform underscores (_) in the response heade This directive was first introduced in the v0.5.0rc32 release. +== lua_check_client_abort == + +'''syntax:''' ''lua_check_client_abort on|off'' + +'''default:''' ''lua_check_client_abort off'' + +'''context:''' ''http, server, location, location-if'' + +This directive controls whether to check for premature client connection abortion. + +When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. + +When TCP keepalive is disabled, it is relying on the client side to close the socket gracefully (by sending a FIN packet or something like that). For (soft) real-time web applications, it is highly recommended to configure the [http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html TCP keepalive] support in your system's TCP stack implementation in order to detect "half-open" TCP connections in time. + +For example, on Linux, you can configure the standard [[HttpCoreModule#listen|listen]] directive in your nginx.conf file like this: + + + listen 80 so_keepalive=2s:2s:8; + + +On FreeBSD, you can only tune the system-wide configuration for TCP keepalive, for example: + + # sysctl net.inet.tcp.keepintvl=2000 + # sysctl net.inet.tcp.keepidle=2000 + +This directive was first introduced in the v0.7.4 release. + +See also [[#ngx.on_abort|ngx.on_abort]]. + = 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. @@ -4301,6 +4330,42 @@ And it will generate the following output: This API was first enabled in the v0.7.0 release. +== ngx.on_abort == +'''syntax:''' ''ok, err = ngx.on_abort(callback)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' + +Registers a user Lua function as the callback which gets called automatically when the client closes the (downstream) connection prematurely. + +Returns 1 if the callback is registered successfully or returns nil and a string describing the error otherwise. + +All the [[#Nginx API for Lua|Nginx API for Lua]] can be used in the callback function because the function is run in a special "light thread", just as those "light threads" created by [[#ngx.thread.spawn|ngx.thread.spawn]]. + +The callback function can decide what to do with the client abortion event all by itself. For example, it can simply ignore the event by doing nothing and the current Lua request handler will continue executing without interruptions. And the callback function can also decide to terminate everything by calling [[#ngx.exit|ngx.exit]], for example, + + + local function my_cleanup() + -- custom cleanup work goes here, like cancelling a pending DB transaction + + -- now abort all the "light threads" running in the current request handler + ngx.exit(499) + end + + local ok, err = ngx.on_abort(my_cleanup) + if not ok then + ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err) + ngx.exit(500) + end + + +When [[#lua_check_client_abort|lua_check_client_abort]] is set to off (which is the default), then this function call will always return the error message "lua_check_client_abort is off". + +According to the current implementation, this function can only be called once in a single request handler; subsequent calls will return the error message "duplicate call". + +This API was first introduced in the v0.7.4 release. + +See also [[#lua_check_client_abort|lua_check_client_abort]]. + == ndk.set_var.DIRECTIVE == '''syntax:''' ''res = ndk.set_var.DIRECTIVE_NAME'' From a55fd25065be558666fb0d97887e28c05b6a9128 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 11 Nov 2012 17:40:31 -0800 Subject: [PATCH 0162/2239] documented the special case that client closes the connection before ngx.req.socket() finishes reading the whole body. --- README | 8 ++++++++ README.markdown | 2 ++ doc/HttpLuaModule.wiki | 2 ++ 3 files changed, 12 insertions(+) diff --git a/README b/README index 67dcc2411b..8bfc1cb3df 100644 --- a/README +++ b/README @@ -1314,6 +1314,14 @@ Directives "light threads" running in the current request's request handler when there is no user callback function registered. + According to the current implementation, however, if the client closes + the connection before the Lua code finishes reading the request body + data via ngx.req.socket, then ngx_lua will neither stop all the running + "light threads" nor call the user callback (if ngx.on_abort has been + called). Instead, the reading operation on ngx.req.socket will just + return the error message "client aborted" as the second return value + (the first return value is surely "nil"). + When TCP keepalive is disabled, it is relying on the client side to close the socket gracefully (by sending a "FIN" packet or something like that). For (soft) real-time web applications, it is highly recommended diff --git a/README.markdown b/README.markdown index 1c9152e88b..26ae89987d 100644 --- a/README.markdown +++ b/README.markdown @@ -1164,6 +1164,8 @@ This directive controls whether to check for premature client connection abortio When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](http://wiki.nginx.org/HttpLuaModule#ngx.on_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket), then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [ngx.on_abort](http://wiki.nginx.org/HttpLuaModule#ngx.on_abort) has been called). Instead, the reading operation on [ngx.req.socket](http://wiki.nginx.org/HttpLuaModule#ngx.req.socket) will just return the error message "client aborted" as the second return value (the first return value is surely `nil`). + When TCP keepalive is disabled, it is relying on the client side to close the socket gracefully (by sending a `FIN` packet or something like that). For (soft) real-time web applications, it is highly recommended to configure the [TCP keepalive](http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html) support in your system's TCP stack implementation in order to detect "half-open" TCP connections in time. For example, on Linux, you can configure the standard [listen](http://wiki.nginx.org/HttpCoreModule#listen) directive in your `nginx.conf` file like this: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9a0223e2d1..de92be6c08 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1119,6 +1119,8 @@ This directive controls whether to check for premature client connection abortio When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [[#ngx.req.socket|ngx.req.socket]], then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [[#ngx.on_abort|ngx.on_abort]] has been called). Instead, the reading operation on [[#ngx.req.socket|ngx.req.socket]] will just return the error message "client aborted" as the second return value (the first return value is surely nil). + When TCP keepalive is disabled, it is relying on the client side to close the socket gracefully (by sending a FIN packet or something like that). For (soft) real-time web applications, it is highly recommended to configure the [http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html TCP keepalive] support in your system's TCP stack implementation in order to detect "half-open" TCP connections in time. For example, on Linux, you can configure the standard [[HttpCoreModule#listen|listen]] directive in your nginx.conf file like this: From 1a44b73fa642f34bd8056c8c6a42c85035d963f1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 12 Nov 2012 11:50:57 -0800 Subject: [PATCH 0163/2239] updated docs to eliminate use of package.seeall in code samples and also to explicitly discourage the use of it. --- README | 44 +++++++++++++++++++----------------- README.markdown | 41 ++++++++++++++++----------------- doc/HttpLuaModule.wiki | 51 +++++++++++++++++++++--------------------- 3 files changed, 70 insertions(+), 66 deletions(-) diff --git a/README b/README index 8bfc1cb3df..0115291176 100644 --- a/README +++ b/README @@ -1356,21 +1356,19 @@ Nginx API for Lua "ndk". These packages are in the default global scope within ngx_lua and are always available within ngx_lua directives. - The packages can be introduced into external Lua modules by using the - package.seeall - () option: + The packages can be introduced into external Lua modules like this: - module("my_module", package.seeall) - - function say(a) ngx.say(a) end + local say = ngx.say - Alternatively, they can be imported to external Lua modules by using - file scoped local Lua variables: + module(...) - local ngx = ngx - module("my_module") + function foo(a) + say(a) + end - function say(a) ngx.say(a) end + Use of the package.seeall + () flag is + strongly discouraged due to its various bad side-effects. It is also possible to directly require the packages in external Lua modules: @@ -5205,7 +5203,7 @@ Data Sharing within an Nginx Worker Here is a complete small example: -- mydata.lua - module("mydata", package.seeall) + module(...) local data = { dog = 3, @@ -5221,7 +5219,7 @@ Data Sharing within an Nginx Worker location /lua { content_lua_by_lua ' - local mydata = require("mydata") + local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; } @@ -5302,7 +5300,7 @@ Known Issues Care should be taken when importing modules and this form should be used: - local xxx = require('xxx') + local xxx = require('xxx') instead of the old deprecated form: require('xxx') @@ -5314,14 +5312,18 @@ Known Issues of Lua modules that use the I/O operations to prevent casual use of module-level global variables that are shared among *all* requests: - getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '"') - end + 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) - Assuming the current Lua module is named "foo.bar", this will guarantee - that local variables in module "foo.bar" functions have been declared as - "local". It prevents undesirable race conditions while accessing such - variables. See Data Sharing within an Nginx Worker for the reasons + 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. Locations Configured by Subrequest Directives of Other Modules diff --git a/README.markdown b/README.markdown index 26ae89987d..1d4cb1a72c 100644 --- a/README.markdown +++ b/README.markdown @@ -1191,22 +1191,19 @@ The various `*_by_lua` and `*_by_lua_file` configuration directives serve as gat The API is exposed to Lua in the form of two standard packages `ngx` and `ndk`. These packages are in the default global scope within ngx_lua and are always available within ngx_lua directives. -The packages can be introduced into external Lua modules by using the [package.seeall](http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall) option: +The packages can be introduced into external Lua modules like this: - module("my_module", package.seeall) - - function say(a) ngx.say(a) end - - -Alternatively, they can be imported to external Lua modules by using file scoped local Lua variables: + local say = ngx.say + module(...) - local ngx = ngx - module("my_module") + function foo(a) + say(a) + end - function say(a) ngx.say(a) end +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. It is also possible to directly require the packages in external Lua modules: @@ -4622,7 +4619,7 @@ Here is a complete small example: -- mydata.lua - module("mydata", package.seeall) + module(...) local data = { dog = 3, @@ -4640,7 +4637,7 @@ and then accessing it from `nginx.conf`: location /lua { content_lua_by_lua ' - local mydata = require("mydata") + local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; } @@ -4680,31 +4677,35 @@ Lua Variable Scope Care should be taken when importing modules and this form should be used: - local xxx = require('xxx') + local xxx = require('xxx') instead of the old deprecated form: - require('xxx') + require('xxx') If the old form is required, force reload the module for every request by using the `package.loaded.` command: - package.loaded.xxx = nil - require('xxx') + package.loaded.xxx = nil + require('xxx') 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: - getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '"') - end + 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) -Assuming the current Lua module is named `foo.bar`, this will guarantee that local variables in module `foo.bar` functions have been declared as `local`. 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 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 de92be6c08..c010917087 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1144,23 +1144,20 @@ The various *_by_lua and *_by_lua_file configuration d The API is exposed to Lua in the form of two standard packages ngx and ndk. These packages are in the default global scope within ngx_lua and are always available within ngx_lua directives. -The packages can be introduced into external Lua modules by using the [http://www.lua.org/manual/5.1/manual.html#pdf-package.seeall package.seeall] option: +The packages can be introduced into external Lua modules like this: - module("my_module", package.seeall) - - function say(a) ngx.say(a) end - - -Alternatively, they can be imported to external Lua modules by using file scoped local Lua variables: + local say = ngx.say - - local ngx = ngx - module("my_module") + module(...) - function say(a) ngx.say(a) end + function foo(a) + say(a) + end +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. + It is also possible to directly require the packages in external Lua modules: @@ -4466,7 +4463,7 @@ Here is a complete small example: -- mydata.lua - module("mydata", package.seeall) + module(...) local data = { dog = 3, @@ -4484,7 +4481,7 @@ and then accessing it from nginx.conf: location /lua { content_lua_by_lua ' - local mydata = require("mydata") + local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; } @@ -4519,32 +4516,36 @@ This issue is due to limitations in the Nginx event model and only appears to af == Lua Variable Scope == Care should be taken when importing modules and this form should be used: - - local xxx = require('xxx') + + local xxx = require('xxx') : instead of the old deprecated form: - - require('xxx') + + require('xxx') : If the old form is required, force reload the module for every request by using the package.loaded. command: - - package.loaded.xxx = nil - require('xxx') + + package.loaded.xxx = nil + require('xxx') 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: - - getmetatable(foo.bar).__newindex = function (table, key, val) - error('Attempt to write to undeclared variable "' .. key .. '"') - end + + 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) -Assuming the current Lua module is named foo.bar, this will guarantee that local variables in module foo.bar functions have been declared as local. 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 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 7c0948a08e8449f7a9ffbc35244954e6aaddac5b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 14 Nov 2012 17:07:24 -0800 Subject: [PATCH 0164/2239] bugfix: ngx.req.clear_header() would result in memory invalid reads when removing the 21st request headers. thanks Umesh Sirsiwal for reporting this issue in github issue #176. --- src/ngx_http_lua_headers_in.c | 36 ++--- t/028-req-header.t | 248 ++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+), 17 deletions(-) diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 5db7dec1a8..44b6a003b2 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -183,6 +183,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, if (value->len == 0) { h->hash = 0; + } else { h->hash = hv->hash; } @@ -380,24 +381,25 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, cur->nelts--; if (cur == l->last) { - if (l->nalloc > 1) { - l->nalloc--; - return NGX_OK; - } + if (cur->nelts == 0) { +#if 1 + part = &l->part; + while (part->next != cur) { + if (part->next == NULL) { + return NGX_ERROR; + } + part = part->next; + } - /* l->nalloc == 1 */ + l->last = part; + part->next = NULL; + l->nalloc = part->nelts; +#endif - part = &l->part; - while (part->next != cur) { - if (part->next == NULL) { - return NGX_ERROR; - } - part = part->next; + } else { + l->nalloc = cur->nelts; } - part->next = NULL; - l->last = part; - return NGX_OK; } @@ -424,7 +426,7 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, cur->nelts--; if (cur == l->last) { - l->nalloc--; + l->nalloc = cur->nelts; } return NGX_OK; @@ -441,12 +443,12 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, new->nelts = cur->nelts - i - 1; new->next = cur->next; - l->nalloc = new->nelts; - cur->nelts = i; cur->next = new; + if (cur == l->last) { l->last = new; + l->nalloc = new->nelts; } return NGX_OK; diff --git a/t/028-req-header.t b/t/028-req-header.t index c483a6ca70..e916e05fab 100644 --- a/t/028-req-header.t +++ b/t/028-req-header.t @@ -789,3 +789,251 @@ My-Foo-Header: Hello World --- response_body My-Foo-Header: Hello World + + +=== TEST 30: clear input header (just more than 20 headers) +--- config + location = /t { + rewrite_by_lua 'ngx.req.clear_header("R")'; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +Q: q\r + +" + + + +=== TEST 31: clear input header (just more than 20 headers, and add more) +--- config + location = /t { + rewrite_by_lua ' + ngx.req.clear_header("R") + for i = 1, 21 do + ngx.req.set_header("foo-" .. i, i) + end + '; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +Q: q\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r + +" + + + +=== TEST 32: clear input header (just more than 21 headers) +--- config + location = /t { + rewrite_by_lua ' + ngx.req.clear_header("R") + ngx.req.clear_header("Q") + '; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +Bah: bah\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r + +" + + + +=== TEST 33: clear input header (just more than 21 headers) +--- config + location = /t { + rewrite_by_lua ' + ngx.req.clear_header("R") + ngx.req.clear_header("Q") + for i = 1, 21 do + ngx.req.set_header("foo-" .. i, i) + end + '; + proxy_pass http://127.0.0.1:$server_port/back; + proxy_set_header Host foo; + #proxy_pass http://127.0.0.1:1234/back; + } + + location = /back { + echo $echo_client_request_headers; + } +--- request +GET /t +--- more_headers eval +my $s = "User-Agent: curl\nBah: bah\n"; + +for my $i ('a' .. 'r') { + $s .= uc($i) . ": " . "$i\n" +} +$s +--- response_body eval +"GET /back HTTP/1.0\r +Host: foo\r +Connection: close\r +User-Agent: curl\r +Bah: bah\r +A: a\r +B: b\r +C: c\r +D: d\r +E: e\r +F: f\r +G: g\r +H: h\r +I: i\r +J: j\r +K: k\r +L: l\r +M: m\r +N: n\r +O: o\r +P: p\r +foo-1: 1\r +foo-2: 2\r +foo-3: 3\r +foo-4: 4\r +foo-5: 5\r +foo-6: 6\r +foo-7: 7\r +foo-8: 8\r +foo-9: 9\r +foo-10: 10\r +foo-11: 11\r +foo-12: 12\r +foo-13: 13\r +foo-14: 14\r +foo-15: 15\r +foo-16: 16\r +foo-17: 17\r +foo-18: 18\r +foo-19: 19\r +foo-20: 20\r +foo-21: 21\r + +" + From 8d92e6c670b65ae4c21d4dbb75a2175ec98ad455 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 20 Nov 2012 11:16:28 -0800 Subject: [PATCH 0165/2239] bugfix: ngx.log() would truncate the log messages with a null character (\0) in it. thanks Wang Xi for reporting this issue. --- src/ngx_http_lua_log.c | 10 ++++------ t/009-log.t | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index 50d593473d..6e3571b033 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -181,7 +181,7 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, } } - buf = lua_newuserdata(L, size + 1); + buf = lua_newuserdata(L, size); p = ngx_copy(buf, name.data, name.len); @@ -245,14 +245,12 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, } } - *p++ = '\0'; - - if (p - buf > (off_t) (size + 1)) { + if (p - buf > (off_t) size) { return luaL_error(L, "buffer error: %d > %d", (int) (p - buf), - (int) (size + 1)); + (int) size); } - ngx_log_error(level, log, 0, "%s%s", ident, buf); + ngx_log_error(level, log, 0, "%s%*s", ident, (size_t) (p - buf), buf); return 0; } diff --git a/t/009-log.t b/t/009-log.t index 130da2031e..17d542b196 100644 --- a/t/009-log.t +++ b/t/009-log.t @@ -8,7 +8,7 @@ log_level('debug'); # to ensure any log-level can be outputed repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 3); +plan tests => repeat_each() * (blocks() * 3 + 4); #no_diff(); #no_long_string(); @@ -435,3 +435,22 @@ GET /log --- error_log bad log level: 9 + + +=== TEST 22: \0 in the log message +--- config + location = /t { + content_by_lua ' + ngx.log(ngx.WARN, "hello\\0world") + ngx.say("ok") + '; + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- error_log eval +"2: hello\0world, client: " + From ca262cb466403030a69b7e109706b30d3d5dc6a4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 20 Nov 2012 14:57:52 -0800 Subject: [PATCH 0166/2239] bumped version to 0.7.5. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 0115291176..f995668a02 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.4 - () released on 11 + This document describes ngx_lua v0.7.5 + () released on 20 November 2012. Synopsis diff --git a/README.markdown b/README.markdown index 1d4cb1a72c..7484776412 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.4](https://github.com/chaoslawful/lua-nginx-module/tags) released on 11 November 2012. +This document describes ngx_lua [v0.7.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 November 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index c010917087..2bd13ebf82 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.4] released on 11 November 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.5] released on 20 November 2012. = Synopsis = From 35b86cd5301b22507850a4adac577b16add4b9ba Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 27 Nov 2012 15:15:11 -0800 Subject: [PATCH 0167/2239] bugfix: ngx.exit(N) threw out exceptions when N was 408, 499, or 444 and the response header was already sent. thanks Kindy Lin for reporting this issue. --- src/ngx_http_lua_control.c | 8 ++- t/101-on-abort.t | 131 ++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 62e144bc1a..4d73a3f299 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -321,8 +321,12 @@ ngx_http_lua_ngx_exit(lua_State *L) return luaL_error(L, "attempt to abort with pending subrequests"); } - if (rc >= NGX_HTTP_SPECIAL_RESPONSE && ctx->headers_sent) { - + if (ctx->headers_sent + && rc >= NGX_HTTP_SPECIAL_RESPONSE + && rc != NGX_HTTP_REQUEST_TIME_OUT + && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST + && rc != NGX_HTTP_CLOSE) + { if (rc != (ngx_int_t) r->headers_out.status) { return luaL_error(L, "attempt to set status %d via ngx.exit after " "sending out the response status %d", (int) rc, diff --git a/t/101-on-abort.t b/t/101-on-abort.t index f710c919e9..a63e85c245 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 15); +plan tests => repeat_each() * (blocks() * 4 + 18); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -623,3 +623,132 @@ delete thread 2 --- no_error_log [error] + + +=== TEST 14: abort with 499 in the user callback, but the header is already sent +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(499) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.send_headers() + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 15: abort with 444 in the user callback, but the header is already sent +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(444) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.send_headers() + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + + + +=== TEST 16: abort with 408 in the user callback, but the header is already sent +--- config + location /t { + lua_check_client_abort on; + content_by_lua ' + local ok, err = ngx.on_abort(function () + ngx.log(ngx.NOTICE, "on abort called") + ngx.exit(408) + end) + + if not ok then + error("cannot set on_abort: " .. err) + end + + ngx.send_headers() + ngx.sleep(0.7) + ngx.log(ngx.NOTICE, "main handler done") + '; + } +--- request +GET /t + +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +lua check broken conn +terminate 2: ok +lua req cleanup +delete thread 2 +delete thread 1 + +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +main handler done +--- error_log +client prematurely closed connection +on abort called + From 15a5793b5f9f19f99be24abdda1ba053a9b944cb Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 27 Nov 2012 16:43:10 -0800 Subject: [PATCH 0168/2239] ngx.exit(N) now no longer throws out a Lua exception when N >= 300 and a response header with a different status code has already been sent (but an error message will still be printed into the error.log file). this change makes Lua code debugging based on ngx.say/ngx.print much easier. thanks Matthieu Tourne for the suggestion. --- src/ngx_http_lua_control.c | 6 +++--- t/005-exit.t | 8 +++++--- t/023-rewrite/exit.t | 5 +++-- t/024-access/exit.t | 5 +++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 4d73a3f299..1b7053c409 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -328,9 +328,9 @@ ngx_http_lua_ngx_exit(lua_State *L) && rc != NGX_HTTP_CLOSE) { if (rc != (ngx_int_t) r->headers_out.status) { - return luaL_error(L, "attempt to set status %d via ngx.exit after " - "sending out the response status %d", (int) rc, - (int) 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", rc, r->headers_out.status); } rc = NGX_HTTP_OK; diff --git a/t/005-exit.t b/t/005-exit.t index c78d402e36..68f226fd48 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 - 1); +plan tests => repeat_each() * (blocks() * 3 + 3); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -66,7 +66,8 @@ GET /lua attempt to set status 404 via ngx.exit after sending out the response status 200 --- no_error_log alert ---- ignore_response +--- response_body +hi @@ -514,7 +515,8 @@ GET /lua } --- request GET /lua ---- ignore_response +--- response_body +Hello World --- error_log attempt to set status 403 via ngx.exit after sending out the response status 200 --- no_error_log diff --git a/t/023-rewrite/exit.t b/t/023-rewrite/exit.t index bc9dc666e9..4664b7131d 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 + 1); +plan tests => repeat_each() * (blocks() * 2 + 3); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -66,7 +66,8 @@ GET /lua GET /lua --- error_log attempt to set status 404 via ngx.exit after sending out the response status 200 ---- ignore_response +--- response_body +hi diff --git a/t/024-access/exit.t b/t/024-access/exit.t index c64c09e0f1..a66f9b0e78 100644 --- a/t/024-access/exit.t +++ b/t/024-access/exit.t @@ -12,7 +12,7 @@ repeat_each(2); #log_level('warn'); #worker_connections(1024); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -60,7 +60,8 @@ GET /lua } --- request GET /lua ---- ignore_response +--- response_body +hi --- no_error_log [alert] --- error_log From 0b838944d1f0a7d3ce422fc9dca01b5368999be9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 27 Nov 2012 18:21:08 -0800 Subject: [PATCH 0169/2239] fixed various issues in the test suite. --- t/023-rewrite/client-abort.t | 21 ++++++++++ t/023-rewrite/on-abort.t | 11 +++++ t/023-rewrite/tcp-socket-timeout.t | 64 ++++++++++++++++++++---------- t/024-access/client-abort.t | 21 ++++++++++ t/024-access/on-abort.t | 11 +++++ t/100-client-abort.t | 22 ++++++++++ t/101-on-abort.t | 14 +++++++ 7 files changed, 142 insertions(+), 22 deletions(-) diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 6b39cc619d..87f916c99e 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -52,6 +52,7 @@ delete thread 1 --- wait: 0.1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -82,6 +83,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -114,6 +116,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -144,6 +147,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -177,6 +181,7 @@ delete thread 1 --- wait: 1.1 --- timeout: 0.2 +--- abort --- ignore_response --- error_log bad things happen @@ -215,6 +220,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -248,6 +254,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -280,6 +287,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -313,6 +321,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -344,6 +353,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -375,6 +385,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -412,6 +423,7 @@ delete thread 1)$ --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -444,6 +456,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -476,6 +489,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -509,6 +523,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -565,6 +580,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -605,6 +621,7 @@ delete thread 2 lua req cleanup --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -645,6 +662,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -750,6 +768,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -786,6 +805,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -822,6 +842,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 9ff61b7582..35d49be0c9 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -67,6 +67,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.5 --- ignore_response --- no_error_log @@ -111,6 +112,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -157,6 +159,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -202,6 +205,8 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort +--- wait: 0.1 --- ignore_response --- no_error_log [error] @@ -247,6 +252,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -296,6 +302,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.5 --- ignore_response --- error_log @@ -357,6 +364,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- wait: 0.2 --- ignore_response --- no_error_log @@ -401,6 +409,7 @@ delete thread 2 lua req cleanup --- timeout: 0.2 +--- abort --- response_body cannot set on_abort: lua_check_client_abort is off --- no_error_log @@ -492,6 +501,7 @@ delete thread 4 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.7 --- ignore_response --- no_error_log @@ -542,6 +552,7 @@ delete thread 2 delete thread 3 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index 28fec9d4d6..2c513c7f90 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -20,7 +20,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 10); +plan tests => repeat_each() * (blocks() * 4 + 14); our $HtmlDir = html_dir; @@ -39,10 +39,11 @@ __DATA__ server_tokens off; lua_socket_connect_timeout 100ms; resolver $TEST_NGINX_RESOLVER; - location /t { + resolver_timeout 1s; + location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("www.google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -54,25 +55,27 @@ __DATA__ content_by_lua return; } --- request -GET /t +GET /t1 --- response_body failed to connect: timeout --- error_log lua tcp socket connect timeout: 100 lua tcp socket connect timed out - +--- timeout: 5 === TEST 2: sock:settimeout() overrides lua_socket_connect_timeout --- config server_tokens off; lua_socket_connect_timeout 60s; + lua_socket_log_errors off; resolver $TEST_NGINX_RESOLVER; - location /t { + resolver_timeout 1s; + location /t2 { rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("www.google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -84,25 +87,30 @@ lua tcp socket connect timed out content_by_lua return; } --- request -GET /t +GET /t2 --- response_body failed to connect: timeout --- error_log lua tcp socket connect timeout: 150 -lua tcp socket connect timed out +--- no_error_log +[error] +[alert] +--- timeout: 5 === TEST 3: sock:settimeout(nil) does not override lua_socket_connect_timeout --- config server_tokens off; + lua_socket_log_errors off; lua_socket_connect_timeout 102ms; resolver $TEST_NGINX_RESOLVER; - location /t { + resolver_timeout 1s; + location /t3 { rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("www.google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -114,12 +122,15 @@ lua tcp socket connect timed out content_by_lua return; } --- request -GET /t +GET /t3 --- response_body failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out +--- no_error_log +[error] +[alert] +--- timeout: 5 @@ -127,12 +138,14 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; + lua_socket_log_errors off; resolver $TEST_NGINX_RESOLVER; - location /t { + resolver_timeout 1s; + location /t4 { rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("www.google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -144,12 +157,15 @@ lua tcp socket connect timed out content_by_lua return; } --- request -GET /t +GET /t4 --- response_body failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out +--- timeout: 5 +--- no_error_log +[error] +[alert] --- timeout: 5 @@ -158,12 +174,14 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; + lua_socket_log_errors off; resolver $TEST_NGINX_RESOLVER; - location /t { + resolver_timeout 1s; + location /t5 { rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("www.taobao.com", 12345) + local ok, err = sock:connect("www.google.com", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -175,12 +193,15 @@ lua tcp socket connect timed out content_by_lua return; } --- request -GET /t +GET /t5 --- response_body failed to connect: timeout --- error_log lua tcp socket connect timeout: 102 -lua tcp socket connect timed out +--- no_error_log +[error] +[alert] +--- timeout: 5 @@ -188,7 +209,6 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 02560302f0..6b7d542b73 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -52,6 +52,7 @@ delete thread 1 --- wait: 0.1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -82,6 +83,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -114,6 +116,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -144,6 +147,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -177,6 +181,7 @@ delete thread 1 --- wait: 1.1 --- timeout: 0.2 +--- abort --- ignore_response --- error_log bad things happen @@ -215,6 +220,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -248,6 +254,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -280,6 +287,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -313,6 +321,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -344,6 +353,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -375,6 +385,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -412,6 +423,7 @@ delete thread 1)$ --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -444,6 +456,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -476,6 +489,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -509,6 +523,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -565,6 +580,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -605,6 +621,7 @@ delete thread 2 lua req cleanup --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -646,6 +663,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -751,6 +769,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -787,6 +806,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -823,6 +843,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index a7630063ff..259ce13817 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -67,6 +67,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.5 --- ignore_response --- no_error_log @@ -111,6 +112,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -157,6 +159,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -202,6 +205,8 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort +--- wait: 0.1 --- ignore_response --- no_error_log [error] @@ -247,6 +252,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -296,6 +302,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.5 --- ignore_response --- error_log @@ -357,6 +364,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- wait: 0.2 --- ignore_response --- no_error_log @@ -401,6 +409,7 @@ delete thread 2 lua req cleanup --- timeout: 0.2 +--- abort --- response_body cannot set on_abort: lua_check_client_abort is off --- no_error_log @@ -492,6 +501,7 @@ delete thread 4 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.7 --- ignore_response --- no_error_log @@ -542,6 +552,7 @@ delete thread 2 delete thread 3 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] diff --git a/t/100-client-abort.t b/t/100-client-abort.t index f52d5fe4b5..c95b8b1834 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -51,6 +51,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -81,6 +82,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -110,6 +112,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -140,6 +143,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -173,6 +177,7 @@ delete thread 1 --- wait: 1.1 --- timeout: 0.2 +--- abort --- ignore_response --- error_log bad things happen @@ -211,6 +216,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -244,6 +250,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -276,6 +283,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -310,6 +318,7 @@ delete thread 1 --- wait: 0.1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -341,6 +350,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -372,6 +382,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -406,6 +417,7 @@ delete thread 1)$ --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -438,6 +450,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -470,6 +483,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -503,6 +517,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -559,6 +574,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -596,6 +612,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -633,6 +650,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -779,6 +797,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -814,6 +833,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -850,6 +870,7 @@ delete thread 1 --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -892,6 +913,7 @@ lua req cleanup --- wait: 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] diff --git a/t/101-on-abort.t b/t/101-on-abort.t index a63e85c245..d3136d8d42 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -64,6 +64,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.7 --- ignore_response --- no_error_log @@ -107,6 +108,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -152,6 +154,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -196,6 +199,8 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort +--- wait: 0.1 --- ignore_response --- no_error_log [error] @@ -240,6 +245,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -286,6 +292,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.5 --- ignore_response --- error_log @@ -346,6 +353,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- wait: 0.2 --- ignore_response --- no_error_log @@ -387,6 +395,7 @@ delete thread 1 lua req cleanup --- timeout: 0.2 +--- abort --- response_body cannot set on_abort: lua_check_client_abort is off --- no_error_log @@ -472,6 +481,7 @@ delete thread 3 lua req cleanup --- timeout: 0.2 +--- abort --- wait: 0.7 --- ignore_response --- no_error_log @@ -521,6 +531,7 @@ delete thread 2 delete thread 3 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -658,6 +669,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -701,6 +713,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] @@ -744,6 +757,7 @@ delete thread 2 delete thread 1 --- timeout: 0.2 +--- abort --- ignore_response --- no_error_log [error] From a9d1383bd92780a635c06c5bf127c66ad33a47b6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 27 Nov 2012 18:21:32 -0800 Subject: [PATCH 0170/2239] minor test case style formatting. --- t/023-rewrite/tcp-socket-timeout.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index 2c513c7f90..aef638957a 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -64,6 +64,7 @@ lua tcp socket connect timed out --- timeout: 5 + === TEST 2: sock:settimeout() overrides lua_socket_connect_timeout --- config server_tokens off; From 9ad04360ceb7882249bb297fb9c9f2666227ed80 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 27 Nov 2012 23:00:50 -0800 Subject: [PATCH 0171/2239] ported all the documentation tweaks from the nginx wiki site. --- README | 17 ++++++++++------- README.markdown | 8 +++++--- doc/HttpLuaModule.wiki | 8 +++++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/README b/README index f995668a02..267d56aecb 100644 --- a/README +++ b/README @@ -250,9 +250,9 @@ Directives 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 inline within nginx.conf such - as those specified by set_by_lua, content_by_lua, access_by_lua, and - rewrite_by_lua will *always* be cached because only the Nginx config + Please note however, that Lua code written inlined within nginx.conf + such as those specified by set_by_lua, content_by_lua, access_by_lua, + and 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. @@ -3891,6 +3891,9 @@ Nginx API for Lua This feature was first introduced in the "v0.3.1rc22" release. + Please note that while internally the key-value pair is set atomically, + the atomicity does not go across the method call boundary. + See also ngx.shared.DICT. ngx.shared.DICT.add @@ -4570,9 +4573,9 @@ Nginx API for Lua context: *rewrite_by_lua*, access_by_lua*, content_by_lua** - Puts the current socket's connection into the cosocket built-in - connection pool and keep it alive until other connect method calls - request it or the associated maximal idle timeout is expired. + Puts the current socket's connection immediately into the cosocket + built-in connection pool and keep it alive until other connect method + calls request it or the associated maximal idle timeout is expired. The first optional argument, "timeout", can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If @@ -5218,7 +5221,7 @@ Data Sharing within an Nginx Worker and then accessing it from "nginx.conf": location /lua { - content_lua_by_lua ' + content_by_lua ' local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; diff --git a/README.markdown b/README.markdown index 7484776412..a08c5b394a 100644 --- a/README.markdown +++ b/README.markdown @@ -240,7 +240,7 @@ 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 inline within nginx.conf +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 cached because only the Nginx config file parser can correctly parse the `nginx.conf` @@ -3560,6 +3560,8 @@ These two forms are fundamentally equivalent. This feature was first introduced in the `v0.3.1rc22` release. +Please note that while internally the key-value pair is set atomically, the atomicity does not go across the method call boundary. + See also [ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT). ngx.shared.DICT.add @@ -4104,7 +4106,7 @@ tcpsock:setkeepalive **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua** -Puts the current socket's connection 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. +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. The first optional argument, `timeout`, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [lua_socket_keepalive_timeout](http://wiki.nginx.org/HttpLuaModule#lua_socket_keepalive_timeout) config directive will be used. If the `0` value is given, then the timeout interval is unlimited. @@ -4636,7 +4638,7 @@ and then accessing it from `nginx.conf`: location /lua { - content_lua_by_lua ' + content_by_lua ' local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 2bd13ebf82..5370432b6f 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -228,7 +228,7 @@ 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 inline within nginx.conf +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 ''always'' be cached because only the Nginx config file parser can correctly parse the nginx.conf @@ -3442,6 +3442,8 @@ These two forms are fundamentally equivalent. This feature was first introduced in the v0.3.1rc22 release. +Please note that while internally the key-value pair is set atomically, the atomicity does not go across the method call boundary. + See also [[#ngx.shared.DICT|ngx.shared.DICT]]. == ngx.shared.DICT.add == @@ -3964,7 +3966,7 @@ This feature was first introduced in the v0.5.0rc1 release. '''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*'' -Puts the current socket's connection 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. +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. The first optional argument, timeout, can be used to specify the maximal idle timeout (in milliseconds) for the current connection. If omitted, the default setting in the [[#lua_socket_keepalive_timeout|lua_socket_keepalive_timeout]] config directive will be used. If the 0 value is given, then the timeout interval is unlimited. @@ -4480,7 +4482,7 @@ and then accessing it from nginx.conf: location /lua { - content_lua_by_lua ' + content_by_lua ' local mydata = require "mydata" ngx.say(mydata.get_age("dog")) '; From 6d7e0c0a5b8d1add55da31d7ebee53b804d73a0a Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 28 Nov 2012 18:26:26 -0800 Subject: [PATCH 0172/2239] bugfix: ngx.location.capture/ngx.location.capture_multi might hang infintely because the parent request might not be waken up right after the first time the post_subrequest callback was called. now we also always skip the special response handler altogether for our subrequests. --- src/ngx_http_lua_subrequest.c | 34 +++- t/023-rewrite/uthread-spawn.t | 338 ++++++++++++++++++++++++++++++++++ t/093-uthread-spawn.t | 330 +++++++++++++++++++++++++++++++++ t/StapThread.pm | 25 ++- 4 files changed, 717 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 5983597d7b..c6fdae617f 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -50,6 +50,7 @@ static ngx_int_t ngx_http_lua_subrequest_resume(ngx_http_request_t *r); 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); /* ngx.location.capture is just a thin wrapper around @@ -839,6 +840,10 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) ctx = psr_data->ctx; if (ctx->run_post_subrequest) { + if (r != r->connection->data) { + r->connection->data = r; + } + return NGX_OK; } @@ -952,13 +957,20 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("free bufs: %p", pr_ctx->free_bufs); } - /* work-around issues in nginx's event module */ + ngx_http_post_request_to_head(pr); if (r != r->connection->data) { r->connection->data = r; } - if (rc == NGX_ERROR) { + if (rc == NGX_ERROR + || rc == NGX_HTTP_CREATED + || rc == NGX_HTTP_NO_CONTENT + || (rc >= NGX_HTTP_SPECIAL_RESPONSE + && rc != NGX_HTTP_CLOSE + && rc != NGX_HTTP_REQUEST_TIME_OUT + && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST)) + { return NGX_OK; } @@ -1471,3 +1483,21 @@ ngx_http_lua_cancel_subreq(ngx_http_request_t *r) r->connection->data = r->parent; } + +static ngx_int_t +ngx_http_post_request_to_head(ngx_http_request_t *r) +{ + ngx_http_posted_request_t *pr; + + pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } + + pr->request = r; + pr->next = r->main->posted_requests; + r->main->posted_requests = pr; + + return NGX_OK; +} + diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index 1ddee930d3..486cfd0489 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1187,3 +1187,341 @@ body: hello world)$ --- no_error_log [error] + + +=== TEST 24: multiple user threads + subrequests returning 404 immediately +--- config + location /t { + rewrite_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + content_by_lua return; + } + + location ~ ^/proxy/(\d+) { + return 404; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +finalize request /proxy/1: rc:404 c:3 a:0 +post subreq: /proxy/1 rc=404, status=0 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +finalize request /proxy/2: rc:404 c:2 a:0 +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:0 c:1 a:1)?$ + +--- response_body +ok +status: 404 +status: 404 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 25: multiple user threads + subrequests returning 404 remotely (no wait) +--- config + location /t { + rewrite_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 5 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + content_by_lua return; + } + + location ~ ^/proxy/(\d+) { + proxy_pass http://127.0.0.1:$server_port/d/$1; + } + + location /d { + return 404; + #echo $uri; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +create 4 in 1 +spawn user thread 4 in 1 +create 5 in 1 +spawn user thread 5 in 1 +create 6 in 1 +spawn user thread 6 in 1 +terminate 1: ok +delete thread 1 +(?:terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +terminate 5: ok +delete thread 5 +terminate 6: ok +delete thread 6|terminate 6: ok +delete thread 6 +terminate 5: ok +delete thread 5 +terminate 4: ok +delete thread 4 +terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2) +terminate 7: ok +delete thread 7 + +--- response_body +ok +status: 404 +status: 404 +status: 404 +status: 404 +status: 404 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 26: multiple user threads + subrequests returning 201 immediately +--- config + location /t { + rewrite_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + content_by_lua return; + } + + location ~ ^/proxy/(\d+) { + content_by_lua 'ngx.exit(201)'; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +terminate 4: ok +delete thread 4 +finalize request /proxy/1: rc:201 c:3 a:0 +post subreq: /proxy/1 rc=201, status=201 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +terminate 5: ok +delete thread 5 +finalize request /proxy/2: rc:201 c:2 a:0 +post subreq: /proxy/2 rc=201, 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:0 c:1 a:1)?$ + +--- response_body +ok +status: 201 +status: 201 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 27: multiple user threads + subrequests returning 204 immediately +--- config + location /t { + rewrite_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + content_by_lua return; + } + + location ~ ^/proxy/(\d+) { + content_by_lua 'ngx.exit(204)'; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' + +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +terminate 4: ok +delete thread 4 +finalize request /proxy/1: rc:204 c:3 a:0 +post subreq: /proxy/1 rc=204, status=204 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +terminate 5: ok +delete thread 5 +finalize request /proxy/2: rc:204 c:2 a:0 +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:0 c:1 a:1)?$ + +--- response_body +ok +status: 204 +status: 204 +--- no_error_log +[error] +--- timeout: 3 + diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index caf4a2a9f0..3234f33881 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1140,3 +1140,333 @@ after --- no_error_log [error] + + +=== TEST 25: multiple user threads + subrequests returning 404 immediately +--- config + location /t { + content_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + return 404; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +finalize request /t: rc:-4 c:4 a:1 +finalize request /proxy/1: rc:404 c:3 a:0 +post subreq: /proxy/1 rc=404, status=0 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +finalize request /proxy/2: rc:404 c:2 a:0 +post subreq: /proxy/2 rc=404, status=0 a=0 +subrequest /proxy/2 done +terminate 3: ok +delete thread 3 +finalize request /t: rc:0 c:1 a:1 +(?:finalize request /t: rc:0 c:1 a:1)?$ + +--- response_body +ok +status: 404 +status: 404 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 26: multiple user threads + subrequests returning 404 remotely (no wait) +--- config + location /t { + content_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 5 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + proxy_pass http://127.0.0.1:$server_port/d/$1; + } + + location /d { + return 404; + #echo $uri; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +create 4 in 1 +spawn user thread 4 in 1 +create 5 in 1 +spawn user thread 5 in 1 +create 6 in 1 +spawn user thread 6 in 1 +terminate 1: ok +delete thread 1 +(?:terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +terminate 5: ok +delete thread 5 +terminate 6: ok +delete thread 6 +|terminate 6: ok +delete thread 6 +terminate 5: ok +delete thread 5 +terminate 4: ok +delete thread 4 +terminate 3: ok +delete thread 3 +terminate 2: ok +delete thread 2)$ + +--- response_body +ok +status: 404 +status: 404 +status: 404 +status: 404 +status: 404 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 27: multiple user threads + subrequests returning 201 immediately +--- config + location /t { + content_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + content_by_lua 'ngx.exit(201)'; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' + +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +finalize request /t: rc:-4 c:4 a:1 +terminate 4: ok +delete thread 4 +finalize request /proxy/1: rc:201 c:3 a:0 +post subreq: /proxy/1 rc=201, status=201 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +terminate 5: ok +delete thread 5 +finalize request /proxy/2: rc:201 c:2 a:0 +post subreq: /proxy/2 rc=201, status=201 a=0 +subrequest /proxy/2 done +terminate 3: ok +delete thread 3 +finalize request /t: rc:0 c:1 a:1 +(?:finalize request /t: rc:0 c:1 a:1)?$ + +--- response_body +ok +status: 201 +status: 201 +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 28: multiple user threads + subrequests returning 204 immediately +--- config + location /t { + content_by_lua ' + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + ngx.say("status: ", res.status) + end + + local threads = {} + for i = 1, 2 do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + content_by_lua 'ngx.exit(204)'; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap eval +"$::GCScript" +. +' +F(ngx_http_finalize_request) { + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); + #if ($rc == -1) { + #print_ubacktrace() + #} +} + +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} + +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +' +--- stap_out_like chop +^create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +terminate 1: ok +delete thread 1 +finalize request /t: rc:-4 c:4 a:1 +terminate 4: ok +delete thread 4 +finalize request /proxy/1: rc:204 c:3 a:0 +post subreq: /proxy/1 rc=204, status=204 a=0 +subrequest /proxy/1 done +terminate 2: ok +delete thread 2 +terminate 5: ok +delete thread 5 +finalize request /proxy/2: rc:204 c:2 a:0 +post subreq: /proxy/2 rc=204, status=204 a=0 +subrequest /proxy/2 done +terminate 3: ok +delete thread 3 +finalize request /t: rc:0 c:1 a:1 +(?:finalize request /t: rc:0 c:1 a:1)?$ + +--- response_body +ok +status: 204 +status: 204 +--- no_error_log +[error] +--- timeout: 3 + diff --git a/t/StapThread.pm b/t/StapThread.pm index 791ea28ec2..dd433d3ba7 100644 --- a/t/StapThread.pm +++ b/t/StapThread.pm @@ -200,12 +200,22 @@ F(ngx_http_lua_run_posted_threads) { } F(ngx_http_finalize_request) { - printf("finalize request: rc:%d c:%d\n", $rc, $r->main->count); + printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); #if ($rc == -1) { #print_ubacktrace() #} } - +F(ngx_http_lua_post_subrequest) { + printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, + $r->headers_out->status, $r == $r->main) + #print_ubacktrace() +} +M(http-subrequest-done) { + printf("subrequest %s done\n", ngx_http_req_uri($r)) +} +M(http-subrequest-wake-parent) { + printf("subrequest wake parent %s\n", ngx_http_req_uri($r->parent)) +} M(http-lua-user-coroutine-create) { p = gen_id($arg2) c = gen_id($arg3) @@ -238,7 +248,7 @@ F(ngx_http_lua_sleep_resume) { M(http-lua-coroutine-done) { t = gen_id($arg2) - printf("terminate coro %d: %s\n", t, $arg3 ? "ok" : "fail") + printf("terminate coro %d: %s, waited by parent:%d, child cocotx: %p\n", t, $arg3 ? "ok" : "fail", $ctx->cur_co_ctx->waited_by_parent, $ctx->cur_co_ctx) //print_ubacktrace() } @@ -250,16 +260,15 @@ 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) } -*/ -F(ngx_http_lua_uthread_wait) { - t = gen_id($L) - printf("lua thread %d waiting\n", t) +M(http-lua-user-thread-wait) { + p = gen_id($arg1) + c = gen_id($arg2) + printf("lua thread %d waiting on %d, child coctx: %p\n", p, c, $sub_coctx) } _EOC_ From d3214ca9c45023f19f41f1311f0d876a86926684 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 28 Nov 2012 23:29:05 -0800 Subject: [PATCH 0173/2239] bugfix: subrequests with error status code did not trigger output header filtering any more. this bad had appeared in the last commit. --- src/ngx_http_lua_subrequest.c | 19 +++++++++++++++++++ t/026-mysql.t | 7 +++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index c6fdae617f..9b8e8a025a 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -971,6 +971,25 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) && rc != NGX_HTTP_REQUEST_TIME_OUT && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST)) { + /* emulate ngx_http_special_response_handler */ + + if (rc > NGX_OK) { + r->err_status = rc; + + r->expect_tested = 1; + r->headers_out.content_type.len = 0; + r->headers_out.content_length_n = 0; + + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + } + return NGX_OK; } diff --git a/t/026-mysql.t b/t/026-mysql.t index 77a71f2b1d..c1fa3b6eed 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -3,9 +3,9 @@ use lib 'lib'; use Test::Nginx::Socket; -repeat_each(1); +repeat_each(2); -plan tests => blocks() * repeat_each() * 2; +plan tests => blocks() * repeat_each() * 3; #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -68,6 +68,9 @@ __DATA__ thread id = \d+ kill status = 200 kill body = {"errcode":0}$ +--- error_log eval +qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizzle upstream} + From e6b20cb2eb82b8a1a04a2af67267718fdd13a682 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 28 Nov 2012 23:32:24 -0800 Subject: [PATCH 0174/2239] feature: added new dtrace static probe http-lua-user-thread-wait. --- dtrace/ngx_lua_provider.d | 3 +++ src/ngx_http_lua_probe.h | 4 ++++ src/ngx_http_lua_uthread.c | 1 + 3 files changed, 8 insertions(+) diff --git a/dtrace/ngx_lua_provider.d b/dtrace/ngx_lua_provider.d index aa23e6fe7f..3767f9bea8 100644 --- a/dtrace/ngx_lua_provider.d +++ b/dtrace/ngx_lua_provider.d @@ -47,6 +47,9 @@ provider nginx_lua { probe http__lua__coroutine__done(ngx_http_request_t *r, void *co, int success); + + /* lua_State *parent, lua_State *child */ + probe http__lua__user__thread__wait(void *parent, void *child); }; diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index df5b632cab..c10eebf108 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -59,6 +59,9 @@ #define ngx_http_lua_probe_coroutine_done(r, co, success) \ NGINX_LUA_HTTP_LUA_COROUTINE_DONE(r, co, success) +#define ngx_http_lua_probe_user_thread_wait(parent, child) \ + NGINX_LUA_HTTP_LUA_USER_THREAD_WAIT(parent, child) + #else /* !(NGX_DTRACE) */ #define ngx_http_lua_probe_info(s) @@ -75,6 +78,7 @@ #define ngx_http_lua_probe_thread_delete(r, thread, ctx) #define ngx_http_lua_probe_run_posted_thread(r, thread, status) #define ngx_http_lua_probe_coroutine_done(r, co, success) +#define ngx_http_lua_probe_user_thread_wait(parent, child) #endif diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 9c8cfa8091..e4cb0fd909 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -175,6 +175,7 @@ ngx_http_lua_uthread_wait(lua_State *L) break; } + ngx_http_lua_probe_user_thread_wait(L, sub_coctx->co); sub_coctx->waited_by_parent = 1; } From 5abd74c3d632c8d6019e3f46c2a13ee583e50382 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 28 Nov 2012 23:33:05 -0800 Subject: [PATCH 0175/2239] minor test file style fixes. --- t/026-mysql.t | 1 - 1 file changed, 1 deletion(-) diff --git a/t/026-mysql.t b/t/026-mysql.t index c1fa3b6eed..eedd8886ac 100644 --- a/t/026-mysql.t +++ b/t/026-mysql.t @@ -73,7 +73,6 @@ qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizz - === TEST 2: no error pages --- http_config upstream backend { From 2ecf5afa8336729a84a3ec72cc6c044c2db886b5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 28 Nov 2012 23:38:31 -0800 Subject: [PATCH 0176/2239] bugfix: ngx.thread.wait() might hang infinitely when more than 4 user "light threads" are created in the same request handler due to the incorrect use of ngx_array_t for ngx_list_t. thanks Junwei Shi for reporting this issue. --- src/ngx_http_lua_common.h | 2 +- src/ngx_http_lua_util.c | 100 +++++++++++++++------- t/093-uthread-spawn.t | 172 +++++++++++++++++++++++++++++++++++++- 3 files changed, 244 insertions(+), 30 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 095397a06a..2dde936001 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -274,7 +274,7 @@ typedef struct ngx_http_lua_ctx_s { ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */ /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ - ngx_array_t *user_co_ctx; /* coroutine contexts for user + ngx_list_t *user_co_ctx; /* coroutine contexts for user coroutines */ ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 2363b3edd6..ac84b9250d 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -324,6 +324,7 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, int inited = 0; int ref; ngx_uint_t i; + ngx_list_part_t *part; ngx_http_lua_co_ctx_t *entry_coctx; ngx_http_lua_co_ctx_t *cc; @@ -358,9 +359,20 @@ ngx_http_lua_del_all_threads(ngx_http_request_t *r, lua_State *L, inited = 1; } - cc = ctx->user_co_ctx->elts; + part = &ctx->user_co_ctx->part; + cc = part->elts; - for (i = 0; i < ctx->user_co_ctx->nelts; i++) { + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + cc = part->elts; + i = 0; + } ref = cc[i].co_ref; @@ -845,7 +857,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_http_lua_del_all_threads(r, L, ctx); if (ctx->user_co_ctx) { - ngx_array_destroy(ctx->user_co_ctx); + /* no way to destroy a list but clean up the whole pool */ ctx->user_co_ctx = NULL; } @@ -1448,6 +1460,7 @@ 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; @@ -1589,32 +1602,37 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r) return NGX_ERROR; } - coctx = ctx->user_co_ctx->elts; + part = &ctx->user_co_ctx->part; + coctx = part->elts; - i = 0; - do { - for ( ;; ) { - if (i >= ctx->user_co_ctx->nelts) { - return NGX_ERROR; - } + for (i = 0; /* void */; i++) { - if (coctx[i].flushing) { - coctx[i].flushing = 0; - ctx->cur_co_ctx = &coctx[i]; + if (i >= part->nelts) { + if (part->next == NULL) { break; } - i++; + part = part->next; + coctx = part->elts; + i = 0; } - rc = ngx_http_lua_flush_resume_helper(r, ctx); - if (rc == NGX_ERROR || rc >= NGX_OK) { - return rc; - } + if (coctx[i].flushing) { + coctx[i].flushing = 0; + ctx->cur_co_ctx = &coctx[i]; + + rc = ngx_http_lua_flush_resume_helper(r, ctx); + if (rc == NGX_ERROR || rc >= NGX_OK) { + return rc; + } - /* rc == NGX_DONE */ + /* rc == NGX_DONE */ - } while (--ctx->flushing_coros); + if (--ctx->flushing_coros == 0) { + break; + } + } + } } if (ctx->flushing_coros) { @@ -2770,6 +2788,7 @@ ngx_http_lua_co_ctx_t * ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx) { ngx_uint_t i; + ngx_list_part_t *part; ngx_http_lua_co_ctx_t *coctx; if (L == ctx->entry_co_ctx.co) { @@ -2780,12 +2799,24 @@ ngx_http_lua_get_co_ctx(lua_State *L, ngx_http_lua_ctx_t *ctx) return NULL; } - coctx = ctx->user_co_ctx->elts; + part = &ctx->user_co_ctx->part; + coctx = part->elts; /* FIXME: we should use rbtree here to prevent O(n) lookup overhead */ - for (i = 0; i < ctx->user_co_ctx->nelts; i++) { - if (L == coctx[i].co) { + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + coctx = part->elts; + i = 0; + } + + if (coctx[i].co == L) { return &coctx[i]; } } @@ -2800,14 +2831,14 @@ ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) ngx_http_lua_co_ctx_t *coctx; if (ctx->user_co_ctx == NULL) { - ctx->user_co_ctx = ngx_array_create(r->pool, 4, - sizeof(ngx_http_lua_co_ctx_t)); + ctx->user_co_ctx = ngx_list_create(r->pool, 4, + sizeof(ngx_http_lua_co_ctx_t)); if (ctx->user_co_ctx == NULL) { return NULL; } } - coctx = ngx_array_push(ctx->user_co_ctx); + coctx = ngx_list_push(ctx->user_co_ctx); if (coctx == NULL) { return NULL; } @@ -2900,6 +2931,7 @@ static void ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { ngx_http_lua_co_ctx_t *cc, *coctx; + ngx_list_part_t *part; ngx_uint_t i; if (ctx->uthreads == 0) { @@ -2915,9 +2947,21 @@ ngx_http_lua_finalize_coroutines(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } if (ctx->user_co_ctx) { - cc = ctx->user_co_ctx->elts; + part = &ctx->user_co_ctx->part; + cc = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + cc = part->elts; + i = 0; + } - for (i = 0; i < ctx->user_co_ctx->nelts; i++) { coctx = &cc[i]; if (coctx->cleanup) { coctx->cleanup(coctx); diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 3234f33881..b86e6f9fb5 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -9,7 +9,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 1); +plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -1470,3 +1470,173 @@ status: 204 [error] --- timeout: 3 + + +=== TEST 29: multiple user threads + subrequests returning 404 remotely (wait) +--- config + location /t { + content_by_lua ' + local n = 5 + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + return res.status + end + + local threads = {} + for i = 1, n do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + for i = 1, n do + local ok, res = ngx.thread.wait(threads[i]) + ngx.say(i, ": ", res) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + proxy_pass http://127.0.0.1:$server_port/d/$1; + } + + location /d { + return 404; + #echo $uri; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap3 eval: $::GCScript +--- stap_out3 +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +create 4 in 1 +spawn user thread 4 in 1 +create 5 in 1 +spawn user thread 5 in 1 +create 6 in 1 +spawn user thread 6 in 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +terminate 5: ok +delete thread 5 +terminate 6: ok +delete thread 6 +terminate 1: ok +delete thread 1 + +--- response_body +1: 404 +2: 404 +3: 404 +4: 404 +5: 404 +ok +--- no_error_log +[error] +--- timeout: 3 + + + +=== TEST 30: multiple user threads + subrequests returning 404 remotely (wait) +--- config + location /t { + content_by_lua ' + local n = 20 + local capture = ngx.location.capture + local insert = table.insert + + local function f(i) + local res = capture("/proxy/" .. i) + return res.status + end + + local threads = {} + for i = 1, n do + local co = ngx.thread.spawn(f, i) + insert(threads, co) + end + + for i = 1, n do + local ok, res = ngx.thread.wait(threads[i]) + ngx.say(i, ": ", res) + end + + ngx.say("ok") + '; + } + + location ~ ^/proxy/(\d+) { + proxy_pass http://127.0.0.1:$server_port/d/$1; + } + + location /d { + echo_sleep 0.001; + echo $uri; + } +--- request + GET /t +--- stap2 eval: $::StapScript +--- stap3 eval: $::GCScript +--- stap_out3 +create 2 in 1 +spawn user thread 2 in 1 +create 3 in 1 +spawn user thread 3 in 1 +create 4 in 1 +spawn user thread 4 in 1 +create 5 in 1 +spawn user thread 5 in 1 +create 6 in 1 +spawn user thread 6 in 1 +terminate 2: ok +delete thread 2 +terminate 3: ok +delete thread 3 +terminate 4: ok +delete thread 4 +terminate 5: ok +delete thread 5 +terminate 6: ok +delete thread 6 +terminate 1: ok +delete thread 1 + +--- response_body +1: 200 +2: 200 +3: 200 +4: 200 +5: 200 +6: 200 +7: 200 +8: 200 +9: 200 +10: 200 +11: 200 +12: 200 +13: 200 +14: 200 +15: 200 +16: 200 +17: 200 +18: 200 +19: 200 +20: 200 +ok +--- no_error_log +[error] +[alert] +--- timeout: 3 + From 7b0d7daca9a91c2ddb4bcdff27188f9f6121cdb8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 1 Dec 2012 17:12:42 -0800 Subject: [PATCH 0177/2239] bugfix: the "light thread" object created by ngx.on_abort() might be prematurely collected by the Lua GC because we did not correctly register its coroutine object into the Lua regsitry table. this bug may crash the Lua VM and nginx workers under load. thanks Zhu Dejiang for reporting this issue. --- src/ngx_http_lua_control.c | 7 ++++++- t/023-rewrite/on-abort.t | 4 ++-- t/101-on-abort.t | 26 ++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 1b7053c409..fefc8027ba 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -386,13 +386,18 @@ ngx_http_lua_on_abort(lua_State *L) lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushvalue(L, -3); + lua_pushvalue(L, -2); + + dd("on_wait thread 1: %p", lua_tothread(L, -1)); + coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); coctx->is_uthread = 1; ctx->on_abort_co_ctx = coctx; + dd("on_wait thread 2: %p", coctx->co); + coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; coctx->parent_co_ctx = ctx->cur_co_ctx; diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 35d49be0c9..9c2ed5482a 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -68,7 +68,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.5 +--- wait: 0.6 --- ignore_response --- no_error_log [error] @@ -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 diff --git a/t/101-on-abort.t b/t/101-on-abort.t index d3136d8d42..4d60acb053 100644 --- a/t/101-on-abort.t +++ b/t/101-on-abort.t @@ -20,7 +20,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 18); +plan tests => repeat_each() * (blocks() * 4 + 16); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; @@ -293,7 +293,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.5 +--- wait: 0.6 --- ignore_response --- error_log client prematurely closed connection @@ -531,6 +531,7 @@ delete thread 2 delete thread 3 --- timeout: 0.2 +--- wait: 0.1 --- abort --- ignore_response --- no_error_log @@ -766,3 +767,24 @@ main handler done client prematurely closed connection on abort called + + +=== TEST 17: GC issue with the on_abort thread object +--- config + location = /t { + lua_check_client_abort on; + content_by_lua ' + ngx.on_abort(function () end) + collectgarbage() + ngx.sleep(60) + '; + } +--- request + GET /t +--- abort +--- timeout: 0.2 +--- ignore_response +--- no_error_log +[error] +[alert] + From ff1949b075fb4a971f62dd5f16699e8311c3b645 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 1 Dec 2012 17:18:22 -0800 Subject: [PATCH 0178/2239] bugfix: the "light thread" object created by ngx.thread.spawn() might be prematurely collected by the Lua GC because we did not correctly register its coroutine object into the Lua regsitry table. this bug may crash the Lua VM and nginx workers under load. thanks Zhu Dejiang for reporting this issue. --- src/ngx_http_lua_uthread.c | 2 +- t/093-uthread-spawn.t | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index e4cb0fd909..253207629d 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -66,7 +66,7 @@ ngx_http_lua_uthread_spawn(lua_State *L) lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushvalue(L, -3); + lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index b86e6f9fb5..ade5edd829 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1640,3 +1640,35 @@ ok [alert] --- timeout: 3 + + +=== TEST 31: simple user thread without I/O +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + ngx.say("f") + end + + ngx.thread.spawn(f) + collectgarbage() + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: ok +delete thread 2 + +--- response_body +f +--- no_error_log +[error] + From 4bd0744086b4f819d328fe0c0957102f60965030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=B0=8F=E7=8E=89?= Date: Mon, 3 Dec 2012 15:36:39 +0800 Subject: [PATCH 0179/2239] Update src/ngx_http_lua_log.c update the comments "print equal ngx.log(ngx.NOTCIE, ...) not ngx.ERR" --- src/ngx_http_lua_log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index 6e3571b033..18258d0978 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -61,7 +61,7 @@ ngx_http_lua_ngx_log(lua_State *L) /** * Override Lua print function, output message to nginx error logs. Equal to - * ngx.log(ngx.ERR, ...). + * ngx.log(ngx.NOTICE, ...). * * @param L Lua state pointer * @retval always 0 (don't return values to Lua) From 4f7eb4f05e94d2cac44897b25fc59e085e153bdf Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 3 Dec 2012 12:05:20 -0800 Subject: [PATCH 0180/2239] made a test case less possible to fail in slow testing modes like "mockeagain w + valgrind memcheck". --- t/093-uthread-spawn.t | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index ade5edd829..8daa98264a 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -15,6 +15,7 @@ $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; #no_shuffle(); +worker_connections(256); no_long_string(); run_tests(); @@ -1638,7 +1639,7 @@ ok --- no_error_log [error] [alert] ---- timeout: 3 +--- timeout: 5 From 857ed86f09697251f70ba2faf9387c68d76fcab3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 4 Dec 2012 20:56:09 -0800 Subject: [PATCH 0181/2239] increased the timeout threshold for the slow tests in slow testing modes. --- t/023-rewrite/uthread-spawn.t | 2 +- t/093-uthread-spawn.t | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/t/023-rewrite/uthread-spawn.t b/t/023-rewrite/uthread-spawn.t index 486cfd0489..e34a27783e 100644 --- a/t/023-rewrite/uthread-spawn.t +++ b/t/023-rewrite/uthread-spawn.t @@ -1350,7 +1350,7 @@ status: 404 status: 404 --- no_error_log [error] ---- timeout: 3 +--- timeout: 6 diff --git a/t/093-uthread-spawn.t b/t/093-uthread-spawn.t index 8daa98264a..8b281ae676 100644 --- a/t/093-uthread-spawn.t +++ b/t/093-uthread-spawn.t @@ -1300,7 +1300,7 @@ status: 404 status: 404 --- no_error_log [error] ---- timeout: 3 +--- timeout: 6 @@ -1546,11 +1546,11 @@ delete thread 1 ok --- no_error_log [error] ---- timeout: 3 +--- timeout: 6 -=== TEST 30: multiple user threads + subrequests returning 404 remotely (wait) +=== TEST 30: multiple user threads + subrequests remotely (wait) --- config location /t { content_by_lua ' @@ -1639,7 +1639,7 @@ ok --- no_error_log [error] [alert] ---- timeout: 5 +--- timeout: 10 From e1dd6ff6624b53c624a548fc319ba590d7499187 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 14:56:13 -0800 Subject: [PATCH 0182/2239] added a test case for a regression introduced by the upstream_pipeline patch of openresty. --- t/014-bugs.t | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index 0ca63a857f..7e9a31718a 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 + 20); +plan tests => repeat_each() * (blocks() * 2 + 21); our $HtmlDir = html_dir; #warn $html_dir; @@ -693,3 +693,34 @@ hi --- response_headers Content-Type: application/json; charset=utf-8 + + +=== TEST 32: hang on upstream_next (from kindy) +--- http_config + upstream xx { + server 127.0.0.1:8888; + server 127.0.0.1:8888; + } + + server { + server_name "xx"; + listen 8888; + + return 444; + } +--- config + location = /t { + proxy_pass http://xx; + } + + location = /bad { + return 444; + } +--- request + GET /t +--- timeout: 1 +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- error_log +upstream prematurely closed connection while reading response header from upstream + From cc57703fbf38a0184dad47132640f0bb944b8702 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 15:24:58 -0800 Subject: [PATCH 0183/2239] updated docs to reflect recent changes. --- README | 15 +++++++-------- README.markdown | 8 +++----- doc/HttpLuaModule.wiki | 8 +++----- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/README b/README index 267d56aecb..21e7e40195 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.5 - () released on 20 - November 2012. + This document describes ngx_lua v0.7.6 + () released on 5 + December 2012. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -639,7 +639,7 @@ Directives rewrite_by_lua ' local res = ngx.location.capture("/check-spam") if res.body == "spam" then - ngx.redirect("/terms-of-use.html") + return ngx.redirect("/terms-of-use.html") end '; @@ -2899,8 +2899,6 @@ Nginx API for Lua This method *must* be called before ngx.send_headers or explicit response body outputs by either ngx.print or ngx.say. - This method never returns. - This method is very much like the rewrite directive with the "redirect" modifier in the standard [[HttpRewriteModule]], for example, this "nginx.conf" snippet @@ -2923,8 +2921,9 @@ Nginx API for Lua return ngx.redirect('/foo?a=3&b=4') - It is strongly recommended to combine the "return" statement with this - call, i.e., "return ngx.redirect(...)". + 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()* diff --git a/README.markdown b/README.markdown index a08c5b394a..4d9a3e2acc 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.5](https://github.com/chaoslawful/lua-nginx-module/tags) released on 20 November 2012. +This document describes ngx_lua [v0.7.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 5 December 2012. Synopsis ======== @@ -580,7 +580,7 @@ can be implemented in ngx_lua as: rewrite_by_lua ' local res = ngx.location.capture("/check-spam") if res.body == "spam" then - ngx.redirect("/terms-of-use.html") + return ngx.redirect("/terms-of-use.html") end '; @@ -2658,8 +2658,6 @@ We can also use the numerical code directly as the second `status` argument: This method *must* be called before [ngx.send_headers](http://wiki.nginx.org/HttpLuaModule#ngx.send_headers) or explicit response body outputs by either [ngx.print](http://wiki.nginx.org/HttpLuaModule#ngx.print) or [ngx.say](http://wiki.nginx.org/HttpLuaModule#ngx.say). -This method never returns. - This method is very much like the [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive with the `redirect` modifier in the standard [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule), for example, this `nginx.conf` snippet @@ -2691,7 +2689,7 @@ URI arguments can be specified as well, for example: return ngx.redirect('/foo?a=3&b=4') -It is strongly recommended to combine the `return` statement with this call, i.e., `return ngx.redirect(...)`. +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 ---------------- diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 5370432b6f..fc4e678499 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.5] released on 20 November 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.6] released on 5 December 2012. = Synopsis = @@ -558,7 +558,7 @@ can be implemented in ngx_lua as: rewrite_by_lua ' local res = ngx.location.capture("/check-spam") if res.body == "spam" then - ngx.redirect("/terms-of-use.html") + return ngx.redirect("/terms-of-use.html") end '; @@ -2578,8 +2578,6 @@ We can also use the numerical code directly as the second status ar This method ''must'' be called before [[#ngx.send_headers|ngx.send_headers]] or explicit response body outputs by either [[#ngx.print|ngx.print]] or [[#ngx.say|ngx.say]]. -This method never returns. - This method is very much like the [[HttpRewriteModule#rewrite|rewrite]] directive with the redirect modifier in the standard [[HttpRewriteModule]], for example, this nginx.conf snippet @@ -2611,7 +2609,7 @@ URI arguments can be specified as well, for example: return ngx.redirect('/foo?a=3&b=4') -It is strongly recommended to combine the return statement with this call, i.e., return ngx.redirect(...). +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()'' From 780b826862ecb6b3daf4a3169e06eb53ec583f96 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 15:34:44 -0800 Subject: [PATCH 0184/2239] refactor: we did not need to reset the on_abort_co_ctx field in reset_ctx. --- src/ngx_http_lua_util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index ac84b9250d..dd67f60778 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -869,8 +869,6 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ctx->entered_access_phase = 0; ctx->entered_content_phase = 0; - ctx->on_abort_co_ctx = NULL; - ctx->exit_code = 0; ctx->exited = 0; ctx->resume_handler = ngx_http_lua_wev_handler; From 164ef98f454f1b7e835821ad11f06c11fb094a07 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 17:44:50 -0800 Subject: [PATCH 0185/2239] feature: the user can now call ngx.exit(444) to abort pending subrequests in other light threads from within a light thread. --- src/ngx_http_lua_control.c | 1 + t/094-uthread-exit.t | 248 ++++++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index fefc8027ba..9c25f2bdb1 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -315,6 +315,7 @@ ngx_http_lua_ngx_exit(lua_State *L) if (ctx->no_abort && rc != NGX_ERROR + && rc != NGX_HTTP_CLOSE && rc != NGX_HTTP_REQUEST_TIME_OUT && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST) { diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index 882e32acee..fe8f5ee688 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -1048,7 +1048,7 @@ after -=== TEST 13: exit in user thread (entry thread is still pending on ngx.location.capture), with pending output +=== TEST 13: exit(0) in user thread (entry thread is still pending on ngx.location.capture), with pending output --- config location /lua { client_body_timeout 12000ms; @@ -1396,3 +1396,249 @@ attempt to abort with pending subrequests [alert] [warn] + + +=== TEST 17: exit(444) in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(444) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +terminate 2: ok +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- no_error_log +[alert] +[error] +[warn] + + + +=== TEST 18: exit(408) in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(408) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +terminate 2: ok +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- no_error_log +[alert] +[error] +[warn] + + + +=== TEST 19: exit(499) in user thread (entry thread is still pending on ngx.location.capture), with pending output +--- config + location /lua { + client_body_timeout 12000ms; + content_by_lua ' + function f() + ngx.say("hello in thread") + ngx.sleep(0.1) + ngx.exit(499) + end + + ngx.say("before") + ngx.thread.spawn(f) + ngx.say("after") + + ngx.location.capture("/sleep") + + ngx.say("end") + '; + } + + location = /sleep { + echo_sleep 0.2; + } +--- request +POST /lua +--- more_headers +Content-Length: 1024 +--- stap2 eval: $::StapScript +--- stap eval +<<'_EOC_' . $::GCScript; + +global timers + +F(ngx_http_free_request) { + println("free request") +} + +M(timer-add) { + if ($arg2 == 200 || $arg2 == 100) { + timers[$arg1] = $arg2 + printf("add timer %d\n", $arg2) + } +} + +M(timer-del) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("delete timer %d\n", tm) + delete timers[$arg1] + } +} + +M(timer-expire) { + tm = timers[$arg1] + if (tm == 200 || tm == 100) { + printf("expire timer %d\n", timers[$arg1]) + delete timers[$arg1] + } +} +_EOC_ + +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +add timer 100 +add timer 200 +expire timer 100 +terminate 2: ok +delete thread 2 +delete thread 1 +delete timer 200 +free request + +--- ignore_response +--- no_error_log +[alert] +[error] +[warn] + From 442b45333300ca0d296f6bb7bdc44e04610e265b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 17:46:43 -0800 Subject: [PATCH 0186/2239] bugfix: when the user callback function registered by ngx.on_abort() discarded the client abort event, the request would be aborted by force when the next client abort event happened. --- src/ngx_http_lua_util.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index dd67f60778..0eb253bd61 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -3122,6 +3122,7 @@ void ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) { ngx_int_t rc; + ngx_event_t *rev; ngx_http_lua_ctx_t *ctx; if (r->done) { @@ -3141,15 +3142,30 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) return; } - if (ctx->on_abort_co_ctx == NULL - || ctx->on_abort_co_ctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) - { + if (ctx->on_abort_co_ctx == NULL) { r->connection->error = 1; ngx_http_lua_request_cleanup(r); ngx_http_finalize_request(r, rc); return; } + if (ctx->on_abort_co_ctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) { + + /* on_abort already run for the current request handler */ + + rev = r->connection->read; + + 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); + return; + } + } + + return; + } + ctx->uthreads++; ctx->resume_handler = ngx_http_lua_on_abort_resume; ctx->on_abort_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; From 930b938d46720f25b38cde4ea70a73cac5b8eeb5 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 18:09:09 -0800 Subject: [PATCH 0187/2239] fixed several test cases which may fail unexpectedly due to timing errors. --- t/065-tcp-socket-timeout.t | 1 + t/098-uthread-wait.t | 1 + t/100-client-abort.t | 1 + 3 files changed, 3 insertions(+) diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index accc1614a5..e7a13169af 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -44,6 +44,7 @@ __DATA__ 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() diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 705262d101..782cc16dec 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -264,6 +264,7 @@ delete thread 3 terminate 1: ok delete thread 1 +--- wait: 0.1 --- response_body f thread created: running g thread created: running diff --git a/t/100-client-abort.t b/t/100-client-abort.t index c95b8b1834..5d8ad87430 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -517,6 +517,7 @@ lua req cleanup delete thread 1 --- timeout: 0.2 +--- wait: 0.1 --- abort --- ignore_response --- no_error_log From 15fac2963bf75a892065f314647471a9aac80143 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 20:43:07 -0800 Subject: [PATCH 0188/2239] feature: setting ngx.status after sending out response headers no longer yield a Lua exception but only leave an error message in the error.log file, which is useful for Lua-land debugging. thanks Matthieu Tourne for requesting this. --- src/ngx_http_lua_misc.c | 6 ++++-- t/015-status.t | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 32bc76abc3..62e316d3f2 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -110,8 +110,10 @@ ngx_http_lua_ngx_set(lua_State *L) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx->headers_sent) { - return luaL_error(L, "attempt to set ngx.status after " - "sending out response headers"); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to set ngx.status after sending out " + "response headers"); + return 0; } /* get the value */ diff --git a/t/015-status.t b/t/015-status.t index 0c439e68eb..a97b51611a 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 => blocks() * repeat_each() * 2; +plan tests => repeat_each() * (blocks() * 2 + 1); #no_diff(); #no_long_string(); @@ -153,3 +153,21 @@ GET /201 --- response_body_like: 500 Internal Server Error --- error_code: 500 + + +=== TEST 10: set ngx.status before headers are sent +--- config + location /t { + content_by_lua ' + ngx.say("ok") + ngx.status = 201 + '; + } +--- request + GET /t +--- response_body +ok +--- error_code: 200 +--- error_log eval +qr/\[error\] .*? attempt to set ngx\.status after sending out response headers/ + From 3583cb08d5694c9336f1c8801cc5bb9e8b36b089 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 21:00:35 -0800 Subject: [PATCH 0189/2239] added tests for the "ngx_slab_alloc() failed: no memory" error message. these require the patch https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.2.4-slab_alloc_no_memory_as_info.patch --- t/043-shdict.t | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/t/043-shdict.t b/t/043-shdict.t index 6d905ae2ef..be87c69e57 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 + 5); +plan tests => repeat_each() * (blocks() * 2 + 7); #no_diff(); no_long_string(); @@ -373,6 +373,9 @@ false expecting exactly two arguments, but only seen 1 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"/ @@ -643,6 +646,9 @@ hello 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"/ From e3d3ec3f58ac7028737d4970e108ee95e9987365 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 5 Dec 2012 21:15:25 -0800 Subject: [PATCH 0190/2239] added more docs regarding using ngx.exit() to abort pending subrequests in other "light threads" and setting ngx.status after sending out the response headers. --- README | 9 ++++++++- README.markdown | 8 +++++++- doc/HttpLuaModule.wiki | 8 +++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README b/README index 21e7e40195..6c2ace93fb 100644 --- a/README +++ b/README @@ -2014,6 +2014,11 @@ Nginx API for Lua ngx.status = ngx.HTTP_CREATED status = ngx.status + Setting "ngx.status" after the response header is sent out has no effect + but leaving an error message in your nginx's error log file: + + attempt to set ngx.status after sending out response headers + ngx.header.HEADER syntax: *ngx.header.HEADER = VALUE* @@ -4801,7 +4806,9 @@ Nginx API for Lua to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call ngx.thread.wait to wait for those "light - thread" to terminate before quitting the "world". + thread" to terminate before quitting the "world". A notable exception + here is that you can abort pending subrequests by calling ngx.exit with + and only with the status code "ngx.ERROR" (-1), 408, 444, or 499. The "light threads" are not scheduled in a pre-emptive way. In other words, no time-slicing is performed automatically. A "light thread" will diff --git a/README.markdown b/README.markdown index 4d9a3e2acc..5fad6b0f05 100644 --- a/README.markdown +++ b/README.markdown @@ -1830,6 +1830,12 @@ before sending out the response headers. status = ngx.status +Setting `ngx.status` after the response header is sent out has no effect but leaving an error message in your nginx's error log file: + + + attempt to set ngx.status after sending out response headers + + ngx.header.HEADER ----------------- **syntax:** *ngx.header.HEADER = VALUE* @@ -4273,7 +4279,7 @@ By default, the corresponding Nginx handler (e.g., [rewrite_by_lua](http://wiki. When the user "light thread" terminates with a Lua error, however, it will not abort other running "light threads" like the "entry thread" does. -Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [ngx.thread.wait](http://wiki.nginx.org/HttpLuaModule#ngx.thread.wait) to wait for those "light thread" to terminate before quitting the "world". +Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [ngx.thread.wait](http://wiki.nginx.org/HttpLuaModule#ngx.thread.wait) to wait for those "light thread" to terminate before quitting the "world". A notable exception here is that you can abort pending subrequests by calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) with and only with the status code `ngx.ERROR` (-1), `408`, `444`, or `499`. The "light threads" are not scheduled in a pre-emptive way. In other words, no time-slicing is performed automatically. A "light thread" will keep running exclusively on the CPU until 1. a (nonblocking) I/O operation cannot be completed in a single run, diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index fc4e678499..909018616c 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1772,6 +1772,12 @@ before sending out the response headers. status = ngx.status +Setting ngx.status after the response header is sent out has no effect but leaving an error message in your nginx's error log file: + + + attempt to set ngx.status after sending out response headers + + == ngx.header.HEADER == '''syntax:''' ''ngx.header.HEADER = VALUE'' @@ -4123,7 +4129,7 @@ By default, the corresponding Nginx handler (e.g., [[#rewrite_by_lua|rewrite_by_ When the user "light thread" terminates with a Lua error, however, it will not abort other running "light threads" like the "entry thread" does. -Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [[#ngx.thread.wait|ngx.thread.wait]] to wait for those "light thread" to terminate before quitting the "world". +Due to the limitation in the Nginx subrequest model, it is not allowed to abort a running Nginx subrequest in general. So it is also prohibited to abort a running "light thread" that is pending on one ore more Nginx subrequests. You must call [[#ngx.thread.wait|ngx.thread.wait]] to wait for those "light thread" to terminate before quitting the "world". A notable exception here is that you can abort pending subrequests by calling [[#ngx.exit|ngx.exit]] with and only with the status code ngx.ERROR (-1), 408, 444, or 499. The "light threads" are not scheduled in a pre-emptive way. In other words, no time-slicing is performed automatically. A "light thread" will keep running exclusively on the CPU until # a (nonblocking) I/O operation cannot be completed in a single run, From 50e41da5d8f378eecafb7df9cca7d3db3c4f8847 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 16:29:25 -0800 Subject: [PATCH 0191/2239] fixed a test case in 020-subrequest.t for slow testing modes. --- t/020-subrequest.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/020-subrequest.t b/t/020-subrequest.t index 9b463ad4cd..d105a8fb8f 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -1464,7 +1464,7 @@ upstream timed out location /proxy { internal; - proxy_read_timeout 100ms; + #proxy_read_timeout 100ms; proxy_buffering on; proxy_pass http://127.0.0.1:19113; } From e83fabb0e5d0870874f90dab879c19e73d18bce3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 16:41:12 -0800 Subject: [PATCH 0192/2239] attempted to fix a test that may fail unexpectedly in the "hup reload" testing mode. --- 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 d105a8fb8f..921bdb0630 100644 --- a/t/020-subrequest.t +++ b/t/020-subrequest.t @@ -85,7 +85,7 @@ DELETE proxy_pass http://127.0.0.1:$server_port/other; } - location /lua { + location /t { content_by_lua ' res = ngx.location.capture("/foo", { method = ngx.HTTP_POST }); @@ -94,7 +94,7 @@ DELETE '; } --- request -GET /lua +GET /t --- response_body POST --- no_error_log From 6969518525a2ad5610c54cb3a2e27f6a0f3a9922 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 18:08:17 -0800 Subject: [PATCH 0193/2239] fixed an english typo in the error message for init_by_lua*. --- src/ngx_http_lua_initby.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index dafa142585..375885caed 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -52,7 +52,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 run init_by_lua*: %s", + ngx_log_error(NGX_LOG_ERR, log, 0, "failed to run init_by_lua*: %s", msg); lua_pop(L, 1); } From 5768a6824d2126dcb1008ba139a30bd660660cf6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 18:15:41 -0800 Subject: [PATCH 0194/2239] feature: added ngx.req.start_time() to return the request starting time in seconds (the milliseconds part is the decimal part just as in ngx.now). thanks Matthieu Tourne for the patch. --- README | 12 +++++ README.markdown | 13 +++++ doc/HttpLuaModule.wiki | 12 +++++ src/ngx_http_lua_time.c | 31 ++++++++++- src/ngx_http_lua_time.h | 2 +- src/ngx_http_lua_util.c | 9 +--- t/062-count.t | 6 +-- t/102-req-start-time.t | 117 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 t/102-req-start-time.t diff --git a/README b/README index 6c2ace93fb..2ab396b765 100644 --- a/README +++ b/README @@ -3472,6 +3472,18 @@ Nginx API for Lua ... end + ngx.req.start_time + syntax: *secs = ngx.req.start_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** + + Returns a floating-point number representing the timestamp (including + milliseconds as the decimal part) when the current request was created. + + The following example is similar to $request_time in Nginx log module : + local request_time = ngx.now() - ngx.req.start_time() + ngx.is_subrequest syntax: *value = ngx.is_subrequest* diff --git a/README.markdown b/README.markdown index 5fad6b0f05..b51fde97af 100644 --- a/README.markdown +++ b/README.markdown @@ -3196,6 +3196,19 @@ Parse the http time string (as returned by [ngx.http_time](http://wiki.nginx.org end +ngx.req.start_time +------------------ +**syntax:** *secs = ngx.req.start_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** + +Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. + +The following example is similar to $request_time in Nginx log module : + + local request_time = ngx.now() - ngx.req.start_time() + + ngx.is_subrequest ----------------- **syntax:** *value = ngx.is_subrequest* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 909018616c..02bc0450d1 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3086,6 +3086,18 @@ Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) int end +== ngx.req.start_time == +'''syntax:''' ''secs = ngx.req.start_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*'' + +Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. + +The following example is similar to $request_time in Nginx log module : + + local request_time = ngx.now() - ngx.req.start_time() + + == ngx.is_subrequest == '''syntax:''' ''value = ngx.is_subrequest'' diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index 9997166b50..e6522597d6 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -4,6 +4,7 @@ #include "ddebug.h" #include "ngx_http_lua_time.h" +#include "ngx_http_lua_util.h" static int ngx_http_lua_ngx_today(lua_State *L); @@ -15,6 +16,7 @@ static int ngx_http_lua_ngx_cookie_time(lua_State *L); static int ngx_http_lua_ngx_http_time(lua_State *L); static int ngx_http_lua_ngx_parse_http_time(lua_State *L); static int ngx_http_lua_ngx_update_time(lua_State *L); +static int ngx_http_lua_ngx_req_start_time(lua_State *L); static int @@ -175,6 +177,25 @@ ngx_http_lua_ngx_parse_http_time(lua_State *L) } +static int +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); + + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + lua_pushnumber(L, (lua_Number) (r->start_sec + r->start_msec / 1000.0L)); + return 1; +} + + void ngx_http_lua_inject_time_api(lua_State *L) { @@ -211,7 +232,15 @@ ngx_http_lua_inject_time_api(lua_State *L) lua_pushcfunction(L, ngx_http_lua_ngx_http_time); lua_setfield(L, -2, "http_time"); - lua_pushcfunction(L, ngx_http_lua_ngx_parse_http_time); + lua_pushcfunction(L, ngx_http_lua_ngx_parse_http_time); lua_setfield(L, -2, "parse_http_time"); } + +void +ngx_http_lua_inject_req_time_api(lua_State *L) +{ + lua_pushcfunction(L, ngx_http_lua_ngx_req_start_time); + lua_setfield(L, -2, "start_time"); +} + diff --git a/src/ngx_http_lua_time.h b/src/ngx_http_lua_time.h index 2ed53868ba..db43d139f1 100644 --- a/src/ngx_http_lua_time.h +++ b/src/ngx_http_lua_time.h @@ -6,7 +6,7 @@ void ngx_http_lua_inject_time_api(lua_State *L); +void ngx_http_lua_inject_req_time_api(lua_State *L); #endif /* NGX_HTTP_LUA_TIME_H */ - diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 0eb253bd61..a551021719 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1999,19 +1999,15 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 20 /* nrec */); /* .req */ + lua_createtable(L, 0 /* narr */, 21 /* nrec */); /* .req */ ngx_http_lua_inject_req_header_api(log, 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); - ngx_http_lua_inject_req_socket_api(L); - ngx_http_lua_inject_req_method_api(L); + ngx_http_lua_inject_req_time_api(L); lua_setfield(L, -2, "req"); } @@ -3271,4 +3267,3 @@ ngx_http_lua_test_expect(ngx_http_request_t *r) return NGX_ERROR; } - diff --git a/t/062-count.t b/t/062-count.t index 53a64c9c4c..a5dbb2025d 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -124,7 +124,7 @@ n = 1 --- request GET /test --- response_body -n = 20 +n = 21 --- no_error_log [error] @@ -146,7 +146,7 @@ n = 20 --- request GET /test --- response_body -n = 20 +n = 21 --- no_error_log [error] @@ -173,7 +173,7 @@ n = 20 --- request GET /test --- response_body -n = 20 +n = 21 --- no_error_log [error] diff --git a/t/102-req-start-time.t b/t/102-req-start-time.t new file mode 100644 index 0000000000..8f3110bad9 --- /dev/null +++ b/t/102-req-start-time.t @@ -0,0 +1,117 @@ +# -*- mode: conf -*- +# 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() * (blocks() * 3); + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: start time +--- config + location = /start { + content_by_lua 'ngx.say(ngx.req.start_time())'; + } +--- request +GET /start +--- response_body_like: ^\d{10,}(\.\d+)?$ +--- no_error_log +[error] + + + +=== TEST 2: start time in set_by_lua +--- config + location = /start { + set_by_lua $a 'return ngx.req.start_time()'; + echo $a; + } +--- request +GET /start +--- response_body_like: ^\d{10,}(\.\d+)?$ +--- no_error_log +[error] + + + +=== TEST 3: request time +--- config + location = /req_time { + content_by_lua ' + ngx.sleep(0.1) + + local req_time = ngx.now() - ngx.req.start_time() + + ngx.say(req_time) + ngx.say(ngx.req.start_time() < ngx.now()) + '; + } +--- request +GET /req_time +--- response_body_like chop +^(?:0\.[12]|0\.099)\d* +true$ +--- no_error_log +[error] + + + +=== TEST 4: request time update +--- config + location = /req_time { + content_by_lua ' + ngx.sleep(0.1) + + local req_time = ngx.now() - ngx.req.start_time() + + ngx.sleep(0.1) + + ngx.update_time() + + local req_time_updated = ngx.now() - ngx.req.start_time() + + ngx.say(req_time) + ngx.say(req_time_updated) + ngx.say(req_time_updated > req_time) + '; + } +--- request +GET /req_time +--- response_body_like chomp +^(?:0\.[12]|0\.099)\d* +0\.\d+ +true$ +--- no_error_log +[error] + + + +=== TEST 5: init_by_lua +--- http_config + init_by_lua ' + time = ngx.req.start_time() + '; +--- config + location = /t { + content_by_lua ' + ngx.say(time) + '; + } +--- request + GET /t +--- response_body +--- no_error_log +[error] +--- SKIP + From 614d6a6ef0b7bf806c2055bdf81a9e93a20c2569 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 21:06:52 -0800 Subject: [PATCH 0195/2239] updated the docs for ngx.req.start_time and ngx.now a bit. --- README | 52 +++++++++++++++++++++++------------------- README.markdown | 49 +++++++++++++++++++++------------------ doc/HttpLuaModule.wiki | 45 ++++++++++++++++++++---------------- 3 files changed, 81 insertions(+), 65 deletions(-) diff --git a/README b/README index 2ab396b765..c74689862b 100644 --- a/README +++ b/README @@ -2117,6 +2117,24 @@ Nginx API for Lua For reading *request* headers, use the ngx.req.get_headers function instead. + ngx.req.start_time + syntax: *secs = ngx.req.start_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** + + Returns a floating-point number representing the timestamp (including + milliseconds as the decimal part) when the current request was created. + + The following example emulates the $request_time variable value + (provided by [[HttpLogModule]]) in pure Lua: + + local request_time = ngx.now() - ngx.req.start_time() + + This function was first introduced in the "v0.7.7" release. + + See also ngx.now and ngx.update_time. + ngx.req.get_method syntax: *method_name = ngx.req.get_method()* @@ -2523,6 +2541,15 @@ Nginx API for Lua ngx.req.clear_header("X-Foo") + ngx.req.clear_header + syntax: *ngx.req.clear_header(header_name)* + + context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, + header_filter_by_lua*, body_filter_by_lua** + + Clear the current request's request header named "header_name". None of + the current request's subrequests will be affected. + ngx.req.read_body syntax: *ngx.req.read_body()* @@ -2816,15 +2843,6 @@ Nginx API for Lua This function was first introduced in the "v0.5.0rc1" release. - ngx.req.clear_header - syntax: *ngx.req.clear_header(header_name)* - - context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, - header_filter_by_lua*, body_filter_by_lua** - - Clear the current request's request header named "header_name". None of - the current request's subrequests will be affected. - ngx.exec syntax: *ngx.exec(uri, args?)* @@ -3392,8 +3410,8 @@ Nginx API for Lua current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). - Use the Nginx core timer_resolution directive to adjust the accuracy or - forcibly update the Nginx time cache by calling ngx.update_time first. + You can forcibly update the Nginx time cache by calling ngx.update_time + first. This API was first introduced in "v0.3.1rc32". @@ -3472,18 +3490,6 @@ Nginx API for Lua ... end - ngx.req.start_time - syntax: *secs = ngx.req.start_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** - - Returns a floating-point number representing the timestamp (including - milliseconds as the decimal part) when the current request was created. - - The following example is similar to $request_time in Nginx log module : - local request_time = ngx.now() - ngx.req.start_time() - ngx.is_subrequest syntax: *value = ngx.is_subrequest* diff --git a/README.markdown b/README.markdown index b51fde97af..b483521414 100644 --- a/README.markdown +++ b/README.markdown @@ -1939,6 +1939,24 @@ Note that `ngx.header` is not a normal Lua table and as such, it is not possible For reading *request* headers, use the [ngx.req.get_headers](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_headers) function instead. +ngx.req.start_time +------------------ +**syntax:** *secs = ngx.req.start_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** + +Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. + +The following example emulates the `$request_time` variable value (provided by [HttpLogModule](http://wiki.nginx.org/HttpLogModule)) in pure Lua: + + + local request_time = ngx.now() - ngx.req.start_time() + + +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.get_method ------------------ **syntax:** *method_name = ngx.req.get_method()* @@ -2367,6 +2385,14 @@ is equivalent to ngx.req.clear_header("X-Foo") +ngx.req.clear_header +-------------------- +**syntax:** *ngx.req.clear_header(header_name)* + +**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** + +Clear the current request's request header named `header_name`. None of the current request's subrequests will be affected. + ngx.req.read_body ----------------- **syntax:** *ngx.req.read_body()* @@ -2571,14 +2597,6 @@ If any request body data has been pre-read into the Nginx core request header bu This function was first introduced in the `v0.5.0rc1` release. -ngx.req.clear_header --------------------- -**syntax:** *ngx.req.clear_header(header_name)* - -**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** - -Clear the current request's request header named `header_name`. None of the current request's subrequests will be affected. - ngx.exec -------- **syntax:** *ngx.exec(uri, args?)* @@ -3121,7 +3139,7 @@ ngx.now 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). -Use the Nginx core [timer_resolution](http://wiki.nginx.org/CoreModule#timer_resolution) directive to adjust the accuracy or forcibly update the Nginx time cache by calling [ngx.update_time](http://wiki.nginx.org/HttpLuaModule#ngx.update_time) first. +You can forcibly update the Nginx time cache by calling [ngx.update_time](http://wiki.nginx.org/HttpLuaModule#ngx.update_time) first. This API was first introduced in `v0.3.1rc32`. @@ -3196,19 +3214,6 @@ Parse the http time string (as returned by [ngx.http_time](http://wiki.nginx.org end -ngx.req.start_time ------------------- -**syntax:** *secs = ngx.req.start_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** - -Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. - -The following example is similar to $request_time in Nginx log module : - - local request_time = ngx.now() - ngx.req.start_time() - - ngx.is_subrequest ----------------- **syntax:** *value = ngx.is_subrequest* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 02bc0450d1..bd3f5f225a 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -1880,6 +1880,23 @@ 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.req.start_time == +'''syntax:''' ''secs = ngx.req.start_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*'' + +Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. + +The following example emulates the $request_time variable value (provided by [[HttpLogModule]]) in pure Lua: + + + local request_time = ngx.now() - ngx.req.start_time() + + +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.get_method == '''syntax:''' ''method_name = ngx.req.get_method()'' @@ -2300,6 +2317,13 @@ is equivalent to ngx.req.clear_header("X-Foo") +== ngx.req.clear_header == +'''syntax:''' ''ngx.req.clear_header(header_name)'' + +'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*'' + +Clear the current request's request header named header_name. None of the current request's subrequests will be affected. + == ngx.req.read_body == '''syntax:''' ''ngx.req.read_body()'' @@ -2494,13 +2518,6 @@ If any request body data has been pre-read into the Nginx core request header bu This function was first introduced in the v0.5.0rc1 release. -== ngx.req.clear_header == -'''syntax:''' ''ngx.req.clear_header(header_name)'' - -'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*'' - -Clear the current request's request header named header_name. None of the current request's subrequests will be affected. - == ngx.exec == '''syntax:''' ''ngx.exec(uri, args?)'' @@ -3017,7 +3034,7 @@ Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.u 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). -Use the Nginx core [[CoreModule#timer_resolution|timer_resolution]] directive to adjust the accuracy or forcibly update the Nginx time cache by calling [[#ngx.update_time|ngx.update_time]] first. +You can forcibly update the Nginx time cache by calling [[#ngx.update_time|ngx.update_time]] first. This API was first introduced in v0.3.1rc32. @@ -3086,18 +3103,6 @@ Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) int end -== ngx.req.start_time == -'''syntax:''' ''secs = ngx.req.start_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*'' - -Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created. - -The following example is similar to $request_time in Nginx log module : - - local request_time = ngx.now() - ngx.req.start_time() - - == ngx.is_subrequest == '''syntax:''' ''value = ngx.is_subrequest'' From c400c31152b5cb00678ae426a6fdd782b6af86a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 21:32:40 -0800 Subject: [PATCH 0196/2239] minor coding style fixes in ngx_http_lua_regex.c. --- src/ngx_http_lua_regex.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 1ee9189417..9135b963bf 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -279,7 +279,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) return luaL_argerror(L, 2, msg); } -#if LUA_HAVE_PCRE_JIT +#if (LUA_HAVE_PCRE_JIT) if (flags & NGX_LUA_RE_MODE_JIT) { @@ -310,7 +310,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre JIT compiling result: %d", jitted); } -# endif /* NGX_DEBUG */ +# endif /* !(NGX_DEBUG) */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); @@ -324,18 +324,18 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } -#else /* LUA_HAVE_PCRE_JIT */ +#else /* !(LUA_HAVE_PCRE_JIT) */ if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); + "your pcre build does not have JIT support and " + "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ From fd51c766cdad726d15254d3ac05f6631587f444b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 6 Dec 2012 21:56:35 -0800 Subject: [PATCH 0197/2239] fixed a test case that uses the hard-coded port 8888 which may not be available especially in the "check leak" testing mode that often runs into port shortage. --- t/014-bugs.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index 7e9a31718a..638381172d 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -698,13 +698,13 @@ Content-Type: application/json; charset=utf-8 === TEST 32: hang on upstream_next (from kindy) --- http_config upstream xx { - server 127.0.0.1:8888; - server 127.0.0.1:8888; + server 127.0.0.1:$TEST_NGINX_PORT; + server 127.0.0.1:$TEST_NGINX_PORT; } server { server_name "xx"; - listen 8888; + listen $TEST_NGINX_PORT; return 444; } From fd7b70de6f60ba7c6512909f6e07a12a159fa3d1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 7 Dec 2012 11:34:08 -0800 Subject: [PATCH 0198/2239] refactor: now we use the TEST_NGINX_SERVER_PORT env consistently in the test suite. --- t/014-bugs.t | 6 ++--- t/022-redirect.t | 7 ++--- t/023-rewrite/redirect.t | 2 -- t/023-rewrite/req-socket.t | 1 - t/023-rewrite/socket-keepalive.t | 17 ++++++------- t/023-rewrite/tcp-socket-timeout.t | 1 - t/023-rewrite/tcp-socket.t | 41 +++++++++++++++--------------- t/023-rewrite/unix-socket.t | 1 - t/024-access/redirect.t | 2 -- t/030-uri-args.t | 8 +++--- t/058-tcp-socket.t | 41 +++++++++++++++--------------- t/059-unix-socket.t | 1 - t/060-lua-memcached.t | 1 - t/061-lua-redis.t | 1 - t/065-tcp-socket-timeout.t | 1 - t/066-socket-receiveuntil.t | 35 +++++++++++++------------ t/067-req-socket.t | 1 - t/068-socket-keepalive.t | 27 ++++++++++---------- t/071-idle-socket.t | 5 ++-- t/083-bad-sock-self.t | 1 - t/084-inclusive-receiveuntil.t | 21 ++++++++------- t/085-if.t | 4 +-- t/087-udp-socket.t | 3 +-- 23 files changed, 100 insertions(+), 128 deletions(-) diff --git a/t/014-bugs.t b/t/014-bugs.t index 638381172d..4b87103832 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -698,13 +698,13 @@ Content-Type: application/json; charset=utf-8 === TEST 32: hang on upstream_next (from kindy) --- http_config upstream xx { - server 127.0.0.1:$TEST_NGINX_PORT; - server 127.0.0.1:$TEST_NGINX_PORT; + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; + server 127.0.0.1:$TEST_NGINX_SERVER_PORT; } server { server_name "xx"; - listen $TEST_NGINX_PORT; + listen $TEST_NGINX_SERVER_PORT; return 444; } diff --git a/t/022-redirect.t b/t/022-redirect.t index 54b903e4a1..261108e038 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -15,9 +15,6 @@ plan tests => repeat_each() * (blocks() * 3 + 1); #no_diff(); #no_long_string(); -$ENV{TEST_NGINX_PORT} ||= 1984; -$ENV{TEST_NGINX_CLIENT_PORT} ||= 1984; - run_tests(); __DATA__ @@ -113,7 +110,7 @@ GET /read echo hello, world; } location /proxy { - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/echo; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/echo; } location /read { content_by_lua ' @@ -153,7 +150,7 @@ Location: http://google.com/foo?bar=3 echo hello, world; } location /proxy { - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/echo; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/echo; } location /read { content_by_lua ' diff --git a/t/023-rewrite/redirect.t b/t/023-rewrite/redirect.t index 687cb3606e..948a5d5bbd 100644 --- a/t/023-rewrite/redirect.t +++ b/t/023-rewrite/redirect.t @@ -15,8 +15,6 @@ plan tests => blocks() * repeat_each() * 3; #no_diff(); #no_long_string(); -$ENV{TEST_NGINX_PORT} ||= 1984; - run_tests(); __DATA__ diff --git a/t/023-rewrite/req-socket.t b/t/023-rewrite/req-socket.t index bebe23feae..f5695f0f9d 100644 --- a/t/023-rewrite/req-socket.t +++ b/t/023-rewrite/req-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3 + 3); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); #$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); diff --git a/t/023-rewrite/socket-keepalive.t b/t/023-rewrite/socket-keepalive.t index 55548473d1..a0f3d95f36 100644 --- a/t/023-rewrite/socket-keepalive.t +++ b/t/023-rewrite/socket-keepalive.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 5 + 8); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; #$ENV{TEST_NGINX_REDIS_PORT} ||= 6379; @@ -177,7 +176,7 @@ received: OK server_tokens off; keepalive_timeout 100ms; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -255,7 +254,7 @@ done location /t { keepalive_timeout 60s; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -331,7 +330,7 @@ done keepalive_timeout 60s; lua_socket_keepalive_timeout 100ms; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -411,7 +410,7 @@ qr/lua tcp socket connection pool size: 30\b/] lua_socket_keepalive_timeout 100ms; lua_socket_pool_size 1; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -490,7 +489,7 @@ qr/lua tcp socket connection pool size: 1\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 0; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -567,7 +566,7 @@ qr/lua tcp socket connection pool size: 30\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 60s; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -647,7 +646,7 @@ qr/lua tcp socket connection pool size: 30\b/] lua_socket_keepalive_timeout 100ms; lua_socket_pool_size 100; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -726,7 +725,7 @@ qr/lua tcp socket connection pool size: 25\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 1000ms; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index aef638957a..f1affcc11c 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -24,7 +24,6 @@ plan tests => repeat_each() * (blocks() * 4 + 14); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; diff --git a/t/023-rewrite/tcp-socket.t b/t/023-rewrite/tcp-socket.t index 200fd79244..747b462b0e 100644 --- a/t/023-rewrite/tcp-socket.t +++ b/t/023-rewrite/tcp-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * 87; our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; @@ -26,7 +25,7 @@ __DATA__ server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -96,7 +95,7 @@ close: nil closed server_tokens off; location /t { #set $port 1234; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -165,7 +164,7 @@ closed server_tokens off; location /t { #set $port 1234; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -340,7 +339,7 @@ lua tcp socket connect timed out server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -460,7 +459,7 @@ attempt to send data on a closed socket server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -530,7 +529,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -600,7 +599,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -682,7 +681,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -760,7 +759,7 @@ close: nil closed lua_socket_buffer_size 1; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -837,7 +836,7 @@ close: nil closed lua_socket_buffer_size 1; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -907,7 +906,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local port = ngx.var.port @@ -1010,7 +1009,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1437,7 +1436,7 @@ close: 1 nil location /t { #set $port 5000; set $port1 $TEST_NGINX_MEMCACHED_PORT; - set $port2 $TEST_NGINX_CLIENT_PORT; + set $port2 $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock1 = ngx.socket.tcp() @@ -1529,7 +1528,7 @@ GET /t server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1601,7 +1600,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1662,7 +1661,7 @@ bad argument #1 to 'send' (bad data type nil found) server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1723,7 +1722,7 @@ bad argument #1 to 'send' (bad data type boolean found) server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1853,7 +1852,7 @@ subrequest: 200, OK\r server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1924,7 +1923,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -1984,7 +1983,7 @@ close: 1 nil server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; rewrite_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/023-rewrite/unix-socket.t b/t/023-rewrite/unix-socket.t index 6daf1bc44a..d5d477814e 100644 --- a/t/023-rewrite/unix-socket.t +++ b/t/023-rewrite/unix-socket.t @@ -7,7 +7,6 @@ repeat_each(2); plan tests => blocks() * repeat_each() * 2; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); no_long_string(); diff --git a/t/024-access/redirect.t b/t/024-access/redirect.t index 92a0721e16..3ca6c03b9a 100644 --- a/t/024-access/redirect.t +++ b/t/024-access/redirect.t @@ -15,8 +15,6 @@ plan tests => blocks() * repeat_each() * 3; #no_diff(); #no_long_string(); -$ENV{TEST_NGINX_PORT} ||= 1984; - run_tests(); __DATA__ diff --git a/t/030-uri-args.t b/t/030-uri-args.t index dc2f8579c2..b614ae8761 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -14,8 +14,6 @@ plan tests => repeat_each() * (blocks() * 2 + 5); no_root_location(); -$ENV{TEST_NGINX_CLIENT_PORT} ||= $ENV{TEST_NGINX} ||= server_port(); - #no_shuffle(); #no_diff(); no_long_string(); @@ -457,7 +455,7 @@ foo: /foo?world ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar") '; - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT; } --- request GET /foo?world @@ -477,7 +475,7 @@ HTTP/1.0 hello ngx.req.set_uri("/bar") ngx.req.set_uri_args({["ca t"] = "%"}) '; - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT; } --- request GET /foo?world @@ -982,7 +980,7 @@ CORE::join("", @k); ngx.req.set_uri_args({a = 3, b = {5, 6}}) ngx.req.set_uri("/bar") '; - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT; } --- request GET /foo?world diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index c665e2fdd6..47eba4f95d 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * 87; our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; @@ -27,7 +26,7 @@ __DATA__ server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -96,7 +95,7 @@ close: nil closed server_tokens off; location /t { #set $port 1234; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -163,7 +162,7 @@ closed server_tokens off; location /t { #set $port 1234; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -331,7 +330,7 @@ lua tcp socket connect timed out server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -445,7 +444,7 @@ attempt to send data on a closed socket server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -513,7 +512,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -581,7 +580,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -661,7 +660,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -737,7 +736,7 @@ close: nil closed lua_socket_buffer_size 1; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -812,7 +811,7 @@ close: nil closed lua_socket_buffer_size 1; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -880,7 +879,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -986,7 +985,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1407,7 +1406,7 @@ close: 1 nil location /t { #set $port 5000; set $port1 $TEST_NGINX_MEMCACHED_PORT; - set $port2 $TEST_NGINX_CLIENT_PORT; + set $port2 $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock1 = ngx.socket.tcp() @@ -1497,7 +1496,7 @@ GET /t server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1567,7 +1566,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1626,7 +1625,7 @@ bad argument #1 to 'send' (bad data type nil found) server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1685,7 +1684,7 @@ bad argument #1 to 'send' (bad data type boolean found) server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1811,7 +1810,7 @@ subrequest: 200, OK\r server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1880,7 +1879,7 @@ close: nil closed server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -1938,7 +1937,7 @@ close: 1 nil server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/059-unix-socket.t b/t/059-unix-socket.t index adf6fa5c2c..63ddb71c74 100644 --- a/t/059-unix-socket.t +++ b/t/059-unix-socket.t @@ -7,7 +7,6 @@ repeat_each(2); plan tests => blocks() * repeat_each() * 2; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); no_long_string(); diff --git a/t/060-lua-memcached.t b/t/060-lua-memcached.t index b39c5a715c..588746bb2f 100644 --- a/t/060-lua-memcached.t +++ b/t/060-lua-memcached.t @@ -10,7 +10,6 @@ plan tests => repeat_each() * (blocks() * 3 + 1); our $HtmlDir = html_dir; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); my $pwd = `pwd`; chomp $pwd; diff --git a/t/061-lua-redis.t b/t/061-lua-redis.t index 9e41264fb7..c1f2363628 100644 --- a/t/061-lua-redis.t +++ b/t/061-lua-redis.t @@ -8,7 +8,6 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3); $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); #log_level "warn"; #worker_connections(1024); diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index e7a13169af..17748706d5 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -28,7 +28,6 @@ plan tests => repeat_each() * (blocks() * 4 + 10); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; diff --git a/t/066-socket-receiveuntil.t b/t/066-socket-receiveuntil.t index 8b8d3285b4..9d6c7c0f8f 100644 --- a/t/066-socket-receiveuntil.t +++ b/t/066-socket-receiveuntil.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); @@ -76,7 +75,7 @@ close: 1 nil --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -145,7 +144,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -213,7 +212,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -284,7 +283,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -355,7 +354,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -426,7 +425,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -498,7 +497,7 @@ close: nil closed server_tokens off; lua_socket_buffer_size 2; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -570,7 +569,7 @@ close: nil closed server_tokens off; lua_socket_buffer_size 1; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -641,7 +640,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -712,7 +711,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -783,7 +782,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -854,7 +853,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -925,7 +924,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -996,7 +995,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -1072,7 +1071,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; lua_socket_buffer_size 1; content_by_lua ' @@ -1149,7 +1148,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; lua_socket_buffer_size 1; content_by_lua ' @@ -1238,7 +1237,7 @@ close: nil closed server_tokens off; lua_socket_buffer_size 3; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") diff --git a/t/067-req-socket.t b/t/067-req-socket.t index ff6f073e1a..ec0d1d0956 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3 + 6); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); #$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); diff --git a/t/068-socket-keepalive.t b/t/068-socket-keepalive.t index fae624c4a1..408fe94caa 100644 --- a/t/068-socket-keepalive.t +++ b/t/068-socket-keepalive.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 5 + 7); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_REDIS_PORT} ||= 6379; @@ -175,7 +174,7 @@ received: OK server_tokens off; keepalive_timeout 100ms; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -251,7 +250,7 @@ done location /t { keepalive_timeout 60s; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -325,7 +324,7 @@ done keepalive_timeout 60s; lua_socket_keepalive_timeout 100ms; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -403,7 +402,7 @@ qr/lua tcp socket connection pool size: 30\b/] lua_socket_keepalive_timeout 100ms; lua_socket_pool_size 1; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -480,7 +479,7 @@ qr/lua tcp socket connection pool size: 1\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 0; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -555,7 +554,7 @@ qr/lua tcp socket connection pool size: 30\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 60s; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -633,7 +632,7 @@ qr/lua tcp socket connection pool size: 30\b/] lua_socket_keepalive_timeout 100ms; lua_socket_pool_size 100; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -710,7 +709,7 @@ qr/lua tcp socket connection pool size: 25\b/] keepalive_timeout 60s; lua_socket_keepalive_timeout 1000ms; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local port = ngx.var.port @@ -1024,7 +1023,7 @@ lua tcp socket keepalive create connection pool for key "B" local test = require "test" local port = ngx.var.port test.go($TEST_NGINX_MEMCACHED_PORT, "foo") - test.go($TEST_NGINX_CLIENT_PORT, "foo") + test.go($TEST_NGINX_SERVER_PORT, "foo") '; } --- user_files @@ -1186,7 +1185,7 @@ lua tcp socket get keepalive peer: using connection local test = require "test" local port = ngx.var.port test.go($TEST_NGINX_MEMCACHED_PORT, 3.14) - test.go($TEST_NGINX_CLIENT_PORT, 3.14) + test.go($TEST_NGINX_SERVER_PORT, 3.14) '; } --- user_files @@ -1233,7 +1232,7 @@ lua tcp socket get keepalive peer: using connection local test = require "test" local port = ngx.var.port test.go($TEST_NGINX_MEMCACHED_PORT, nil) - test.go($TEST_NGINX_CLIENT_PORT, nil) + test.go($TEST_NGINX_SERVER_PORT, nil) '; } --- user_files @@ -1274,7 +1273,7 @@ bad argument #3 to 'connect' (bad "pool" option type: nil) local test = require "test" local port = ngx.var.port test.go($TEST_NGINX_MEMCACHED_PORT, {}) - test.go($TEST_NGINX_CLIENT_PORT, {}) + test.go($TEST_NGINX_SERVER_PORT, {}) '; } --- user_files @@ -1315,7 +1314,7 @@ bad argument #3 to 'connect' (bad "pool" option type: table) local test = require "test" local port = ngx.var.port test.go($TEST_NGINX_MEMCACHED_PORT, true) - test.go($TEST_NGINX_CLIENT_PORT, false) + test.go($TEST_NGINX_SERVER_PORT, false) '; } --- user_files diff --git a/t/071-idle-socket.t b/t/071-idle-socket.t index 55c9755b2c..db9fde19e5 100644 --- a/t/071-idle-socket.t +++ b/t/071-idle-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); @@ -24,7 +23,7 @@ __DATA__ --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() @@ -304,7 +303,7 @@ close: 1 nil --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' local sock = ngx.socket.tcp() diff --git a/t/083-bad-sock-self.t b/t/083-bad-sock-self.t index 6e85699d9b..50b9cdd921 100644 --- a/t/083-bad-sock-self.t +++ b/t/083-bad-sock-self.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); #$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); diff --git a/t/084-inclusive-receiveuntil.t b/t/084-inclusive-receiveuntil.t index 2fd248e3e4..ad56bdb163 100644 --- a/t/084-inclusive-receiveuntil.t +++ b/t/084-inclusive-receiveuntil.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (blocks() * 3); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; no_long_string(); @@ -24,7 +23,7 @@ __DATA__ --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -96,7 +95,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -168,7 +167,7 @@ close: nil closed server_tokens off; lua_socket_buffer_size 1; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -240,7 +239,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -311,7 +310,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -382,7 +381,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -453,7 +452,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -520,7 +519,7 @@ bad "inclusive" option value type: string --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; content_by_lua ' -- collectgarbage("collect") @@ -587,7 +586,7 @@ bad "inclusive" option value type: string --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; lua_socket_buffer_size 1; content_by_lua ' @@ -664,7 +663,7 @@ close: nil closed --- config server_tokens off; location /t { - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; lua_socket_buffer_size 1; content_by_lua ' diff --git a/t/085-if.t b/t/085-if.t index 883f3c3196..1323a48171 100644 --- a/t/085-if.t +++ b/t/085-if.t @@ -12,8 +12,6 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 2); -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); - #no_diff(); #no_long_string(); run_tests(); @@ -188,7 +186,7 @@ This test case requires the following patch for the nginx core: http://mailman.nginx.org/pipermail/nginx-devel/2012-June/002374.html --- config location /proxy-pass-uri { - proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/; + proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/; set $true 1; diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 213814a439..87933c6cc8 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -9,7 +9,6 @@ plan tests => repeat_each() * (3 * blocks() + 6); our $HtmlDir = html_dir; -$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; @@ -148,7 +147,7 @@ GET /t server_tokens off; location /t { #set $port 5000; - set $port $TEST_NGINX_CLIENT_PORT; + set $port $TEST_NGINX_SERVER_PORT; #set $port 1234; content_by_lua ' From b39743aa57364dafcd93ad8962aafa6c4a12fe53 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 7 Dec 2012 20:44:01 -0800 Subject: [PATCH 0199/2239] bugfix: when a user coroutine or user "light thread" dies with an error, our Lua backtrace dumper written in C may access one of its dead parent threads which could lead to segmentation faults. --- src/ngx_http_lua_coroutine.c | 6 +++++- src/ngx_http_lua_util.c | 2 +- t/098-uthread-wait.t | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_coroutine.c b/src/ngx_http_lua_coroutine.c index 5ab38e7803..21eeb76735 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -260,7 +260,11 @@ ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) "coroutine.wrap = function(f)\n" "local co = create(f)\n" "return function(...) return select(2, resume(co, ...)) end\n" - "end"; + "end\n" +#if 0 + "debug.sethook(function () collectgarbage() end, 'rl', 1)" +#endif + ; rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "coroutine.wrap"); } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index a551021719..1636197f77 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2660,7 +2660,7 @@ ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, /* check if the coroutine has a parent coroutine*/ coctx = coctx->parent_co_ctx; - if (!coctx) { + if (!coctx || coctx->co_status == NGX_HTTP_LUA_CO_DEAD) { break; } diff --git a/t/098-uthread-wait.t b/t/098-uthread-wait.t index 782cc16dec..8155653a12 100644 --- a/t/098-uthread-wait.t +++ b/t/098-uthread-wait.t @@ -1187,3 +1187,39 @@ delete thread 1 --- 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 + + +=== TEST 20: lua backtrace dumper may access dead parent coroutines +--- config + location /lua { + content_by_lua ' + function f() + ngx.sleep(0.1) + collectgarbage() + error("f done") + end + + ngx.thread.spawn(f) + ngx.say("ok") + + collectgarbage() + '; + } +--- request +GET /lua +--- stap2 eval: $::StapScript +--- stap eval: $::GCScript +--- stap_out +create 2 in 1 +spawn user thread 2 in 1 +terminate 1: ok +delete thread 1 +terminate 2: fail +delete thread 2 + +--- response_body +ok + +--- error_log +lua user thread aborted: runtime error: [string "content_by_lua"]:5: f done + From 94d950eed745113f2b358760211940f83c55c6aa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Dec 2012 00:06:42 -0800 Subject: [PATCH 0200/2239] bumped version to 0.7.7. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index c74689862b..a11d320090 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.6 - () released on 5 + This document describes ngx_lua v0.7.7 + () released on 8 December 2012. Synopsis diff --git a/README.markdown b/README.markdown index b483521414..0fb4382a0a 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.6](https://github.com/chaoslawful/lua-nginx-module/tags) released on 5 December 2012. +This document describes ngx_lua [v0.7.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 December 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index bd3f5f225a..9084d4bcfa 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.6] released on 5 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.7] released on 8 December 2012. = Synopsis = From 46e32a2915d01a445322dfebb36a087a2f7a6181 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Dec 2012 17:07:18 -0800 Subject: [PATCH 0201/2239] bugfix: ngx.req.set_body_file() might lead to memory issues because it directly used the storage of lua strings allocated by the lua GC (we should allocate a new memory block on the nginx side and copy the string data over). --- src/ngx_http_lua_req_body.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index f0c20f2cb7..047545de7d 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -795,6 +795,7 @@ ngx_http_lua_pool_cleanup_file(ngx_pool_t *p, ngx_fd_t fd) static int ngx_http_lua_ngx_req_set_body_file(lua_State *L) { + u_char *p; ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; @@ -817,7 +818,24 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); } - name.data = (u_char *) luaL_checklstring(L, 1, &name.len); + 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); + + if (r == NULL) { + return luaL_error(L, "request object not found"); + } + + name.data = ngx_palloc(r->pool, name.len + 1); + if (name.data == NULL) { + return luaL_error(L, "out of memory"); + } + + ngx_memcpy(name.data, p, name.len); + name.data[name.len] = '\0'; if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); @@ -829,15 +847,6 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) dd("clean: %d", (int) clean); - 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, "request object not found"); - } - if (r->request_body == NULL) { #if 1 From 477f82efcc295a03c18caf58b13ae116e0001cbd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Dec 2012 21:47:05 -0800 Subject: [PATCH 0202/2239] made the tests for ngx.on_abort() less possible to fail due to random timing issues. --- t/023-rewrite/on-abort.t | 2 +- t/024-access/on-abort.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index 9c2ed5482a..cf0c760624 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -68,7 +68,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.6 +--- wait: 0.7 --- ignore_response --- no_error_log [error] diff --git a/t/024-access/on-abort.t b/t/024-access/on-abort.t index 259ce13817..46e4096ba5 100644 --- a/t/024-access/on-abort.t +++ b/t/024-access/on-abort.t @@ -68,7 +68,7 @@ lua req cleanup --- timeout: 0.2 --- abort ---- wait: 0.5 +--- wait: 0.7 --- ignore_response --- no_error_log [error] From d54a03ebd2d45aee9d50d1175bbea99578efb1b1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Dec 2012 22:14:54 -0800 Subject: [PATCH 0203/2239] made the tests in uthread-exec.t less possible to fail the systemtap subtest on slow machines. --- t/023-rewrite/uthread-exec.t | 1 + t/024-access/uthread-exec.t | 1 + t/095-uthread-exec.t | 1 + 3 files changed, 3 insertions(+) diff --git a/t/023-rewrite/uthread-exec.t b/t/023-rewrite/uthread-exec.t index ec10f8c75b..a563716aa1 100644 --- a/t/023-rewrite/uthread-exec.t +++ b/t/023-rewrite/uthread-exec.t @@ -344,6 +344,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log diff --git a/t/024-access/uthread-exec.t b/t/024-access/uthread-exec.t index 48eace209d..10982a60f6 100644 --- a/t/024-access/uthread-exec.t +++ b/t/024-access/uthread-exec.t @@ -344,6 +344,7 @@ terminate 3: ok delete thread 3 free request +--- wait: 0.1 --- response_body end --- error_log diff --git a/t/095-uthread-exec.t b/t/095-uthread-exec.t index 0089d44fd1..1a28861df0 100644 --- a/t/095-uthread-exec.t +++ b/t/095-uthread-exec.t @@ -337,6 +337,7 @@ delete thread 2 delete thread 1 free request +--- wait: 0.1 --- response_body end --- error_log From d4eb39b40e0d783af9821a27a93df2573910625b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 8 Dec 2012 23:39:19 -0800 Subject: [PATCH 0204/2239] bumped version to 0.7.8. --- README | 2 +- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index a11d320090..2e14c30cce 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ Status This module is under active development and is production ready. Version - This document describes ngx_lua v0.7.7 + This document describes ngx_lua v0.7.8 () released on 8 December 2012. diff --git a/README.markdown b/README.markdown index 0fb4382a0a..3e90b58036 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.7](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 December 2012. +This document describes ngx_lua [v0.7.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 December 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9084d4bcfa..c8007495fa 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.7] released on 8 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.8] released on 8 December 2012. = Synopsis = From 457cdf79e1dedf957fd1811c06c10e1740716a54 Mon Sep 17 00:00:00 2001 From: Gosuke Miyashita Date: Mon, 10 Dec 2012 14:29:42 +0900 Subject: [PATCH 0205/2239] Fix date format --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 2e14c30cce..3ec084ea4a 100644 --- a/README +++ b/README @@ -3474,7 +3474,7 @@ Nginx API for Lua the time stamp in seconds (like those returned from ngx.time). ngx.say(ngx.http_time(1290079655)) - -- yields "Thu, 18 Nov 10 11:27:35 GMT" + -- yields "Thu, 18 Nov 2010 11:27:35 GMT" ngx.parse_http_time syntax: *sec = ngx.parse_http_time(str)* @@ -3485,7 +3485,7 @@ Nginx API for Lua 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. - local time = ngx.parse_http_time("Thu, 18 Nov 10 11:27:35 GMT") + local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") if time == nil then ... end From eb3a36bb48f74f2e7ee1a022b0e0b77c558d7b22 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 10 Dec 2012 12:27:47 -0800 Subject: [PATCH 0206/2239] updated docs to reflect recent changes. --- README | 2 +- README.markdown | 6 +++--- doc/HttpLuaModule.wiki | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index 3ec084ea4a..7dacdcee09 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ Status Version This document describes ngx_lua v0.7.8 - () released on 8 + () released on 9 December 2012. Synopsis diff --git a/README.markdown b/README.markdown index 3e90b58036..5efaee6ed8 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.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 8 December 2012. +This document describes ngx_lua [v0.7.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 December 2012. Synopsis ======== @@ -3196,7 +3196,7 @@ Returns a formated string can be used as the http header time (for example, bein ngx.say(ngx.http_time(1290079655)) - -- yields "Thu, 18 Nov 10 11:27:35 GMT" + -- yields "Thu, 18 Nov 2010 11:27:35 GMT" ngx.parse_http_time @@ -3208,7 +3208,7 @@ ngx.parse_http_time 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. - local time = ngx.parse_http_time("Thu, 18 Nov 10 11:27:35 GMT") + local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") if time == nil then ... end diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index c8007495fa..8c2013d60c 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.8] released on 8 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.8] released on 9 December 2012. = Synopsis = @@ -3086,7 +3086,7 @@ Returns a formated string can be used as the http header time (for example, bein ngx.say(ngx.http_time(1290079655)) - -- yields "Thu, 18 Nov 10 11:27:35 GMT" + -- yields "Thu, 18 Nov 2010 11:27:35 GMT" == ngx.parse_http_time == @@ -3097,7 +3097,7 @@ Returns a formated string can be used as the http header time (for example, bein 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. - local time = ngx.parse_http_time("Thu, 18 Nov 10 11:27:35 GMT") + local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") if time == nil then ... end From 543169dfbd8fb85baa4f430a0936daf5586c31d3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 14 Dec 2012 15:00:14 -0800 Subject: [PATCH 0207/2239] bugfix: typo in the error message when accessing an nginx variable that has not been defined. --- src/ngx_http_lua_variable.c | 6 +++--- t/001-set.t | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index cbde7ec698..3b63366c31 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -274,8 +274,8 @@ ngx_http_lua_var_set(lua_State *L) /* variable not found */ return luaL_error(L, "varaible \"%s\" not found for writing; " - "maybe it is a built-in variable that is not changeable " - "or you sould have used \"set $%s '';\" earlier " - "in the config file", lowcase, lowcase); + "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", lowcase, lowcase); } diff --git a/t/001-set.t b/t/001-set.t index 80dd24bc2a..6b53f4cc65 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 sould have used "set $b '';" earlier in the config file +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 @@ -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 sould have used "set $arg_foo '';" earlier in the config file +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 From 59fc4aea8c4aca59249c83cc55250947a6a968f1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Dec 2012 00:06:04 -0800 Subject: [PATCH 0208/2239] bugfix: ngx.status assignment would always be overridden by the later ngx.exit() calls for HTTP 1.0 requests if lua_http10_buffering is on (the default setting). thanks chenshu for reporting this in github issue #193. --- src/ngx_http_lua_util.c | 5 ++++- t/015-status.t | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 1636197f77..ba9072a329 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -2120,7 +2120,10 @@ ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r, ctx->exit_code); #if 1 - if (!ctx->headers_sent && ctx->exit_code >= NGX_HTTP_OK) { + if (!ctx->headers_sent + && r->headers_out.status == 0 + && ctx->exit_code >= NGX_HTTP_OK) + { r->headers_out.status = ctx->exit_code; } #endif diff --git a/t/015-status.t b/t/015-status.t index a97b51611a..89289d4d55 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 + 1); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); #no_long_string(); @@ -171,3 +171,22 @@ ok --- error_log eval qr/\[error\] .*? attempt to set ngx\.status after sending out response headers/ + + +=== TEST 11: http 1.0 and ngx.status +--- config + location /nil { + content_by_lua ' + ngx.status = ngx.HTTP_UNAUTHORIZED + ngx.say("invalid request") + ngx.exit(ngx.HTTP_OK) + '; + } +--- request +GET /nil HTTP/1.0 +--- response_body +invalid request +--- error_code: 401 +--- no_error_log +[error] + From 6eeb8fb81cd648737a9178d381815325d58b1991 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Dec 2012 22:57:50 -0800 Subject: [PATCH 0209/2239] minor coding style fixes. --- 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 3b63366c31..adbd9f36cb 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -276,6 +276,7 @@ ngx_http_lua_var_set(lua_State *L) return luaL_error(L, "varaible \"%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", lowcase, lowcase); + "in the config file to define it first", + lowcase, lowcase); } From 362fcfe460e8f2422ede0633c40f1e9acb0e5f65 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 22 Dec 2012 22:58:51 -0800 Subject: [PATCH 0210/2239] documented the request body automatic inheritance behavior in ngx.location.capture; also bumped version to 0.7.9. --- README | 8 ++++++-- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README b/README index 7dacdcee09..9dd2612390 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.8 - () released on 9 + This document describes ngx_lua v0.7.9 + () released on 22 December 2012. Synopsis @@ -1928,6 +1928,10 @@ 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). + 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, diff --git a/README.markdown b/README.markdown index 5efaee6ed8..727cb8a75f 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.8](https://github.com/chaoslawful/lua-nginx-module/tags) released on 9 December 2012. +This document describes ngx_lua [v0.7.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 December 2012. Synopsis ======== @@ -1748,6 +1748,8 @@ 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). + 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 8c2013d60c..d35d7bdc0c 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.8] released on 9 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.9] released on 22 December 2012. = Synopsis = @@ -1692,6 +1692,8 @@ 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). + 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 cf18fcbbb67c1ffbd018befd0fcd310f550ec080 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Dec 2012 14:37:06 -0800 Subject: [PATCH 0211/2239] docs: explained why "local foo = require 'foo'" is required to load a Lua module. thanks rkearsley for asking. --- README | 17 ++++++++++++----- README.markdown | 9 ++------- doc/HttpLuaModule.wiki | 9 ++------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/README b/README index 9dd2612390..0659eb793f 100644 --- a/README +++ b/README @@ -5328,16 +5328,23 @@ Known Issues use LuaJIT 2.0, which supports a fully resumable VM, to avoid this. Lua Variable Scope - Care should be taken when importing modules and this form should be - used: + Care must be taken when importing modules and this form should be used: local xxx = require('xxx') instead of the old deprecated form: require('xxx') - If the old form is required, force reload the module for every request - by using the "package.loaded." command: package.loaded.xxx = nil - require('xxx') + 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 diff --git a/README.markdown b/README.markdown index 727cb8a75f..48753f8f97 100644 --- a/README.markdown +++ b/README.markdown @@ -4700,7 +4700,7 @@ Lua Coroutine Yielding/Resuming Lua Variable Scope ------------------ -Care should be taken when importing modules and this form should be used: +Care must be taken when importing modules and this form should be used: local xxx = require('xxx') @@ -4712,12 +4712,7 @@ Care should be taken when importing modules and this form should be used: require('xxx') - If the old form is required, force reload the module for every request by using the `package.loaded.` command: - - - package.loaded.xxx = nil - require('xxx') - +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: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index d35d7bdc0c..18a94ecc7e 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -4539,7 +4539,7 @@ This issue is due to limitations in the Nginx event model and only appears to af * 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. == Lua Variable Scope == -Care should be taken when importing modules and this form should be used: +Care must be taken when importing modules and this form should be used: local xxx = require('xxx') @@ -4551,12 +4551,7 @@ Care should be taken when importing modules and this form should be used: require('xxx') -: If the old form is required, force reload the module for every request by using the package.loaded. command: - - - package.loaded.xxx = nil - require('xxx') - +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: From d1613a64751d9b677d2605b42cf68bbfe70f688c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Dec 2012 16:48:33 -0800 Subject: [PATCH 0212/2239] feature: automatically detect LuaJIT 2.0 on FreeBSD by default. thanks rkearsley for the patch. --- config | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/config b/config index 6028f2d02e..c2d2fa166b 100644 --- a/config +++ b/config @@ -104,7 +104,7 @@ END if [ $ngx_found = no ]; then # FreeBSD - ngx_feature="Lua library in /usr/local/../lua51/" + ngx_feature="Lua library in /usr/local/*/lua51/" ngx_feature_path="/usr/local/include/lua51" if [ $NGX_RPATH = YES ]; then ngx_feature_libs="-R/usr/local/lib/lua51 -L/usr/local/lib/lua51 -llua -lm" @@ -126,6 +126,18 @@ END . auto/feature fi + if [ $ngx_found = no ]; then + # FreeBSD with luajit-2.0 from ports collection + ngx_feature="LuaJIT library in /usr/local/" + ngx_feature_path="/usr/local/include/luajit-2.0" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lluajit-5.1 -lm" + else + ngx_feature_libs="-L/usr/local/lib -lluajit-5.1 -lm" + fi + . auto/feature + fi +. if [ $ngx_found = no ]; then # Gentoo with LuaJIT-2.0 ngx_feature="LuaJIT library in /usr/" From 508486684294e450773c4243b006bf40c93e9837 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 23 Dec 2012 18:10:53 -0800 Subject: [PATCH 0213/2239] updated the tests in 005-exit.t for nginx 1.2.6+. --- t/005-exit.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/005-exit.t b/t/005-exit.t index 68f226fd48..fdd82730c4 100644 --- a/t/005-exit.t +++ b/t/005-exit.t @@ -482,7 +482,7 @@ hello --- request GET /lua --- error_code: 501 ---- response_body_like: 501 Method Not Implemented +--- response_body_like: 501 (?:Method )?Not Implemented --- no_error_log [error] @@ -498,7 +498,7 @@ GET /lua --- request GET /lua --- error_code: 501 ---- response_body_like: 501 Method Not Implemented +--- response_body_like: 501 (?:Method )?Not Implemented --- no_error_log [error] From eabefc7970a1c3d50f046efad5555ef4067563ff Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Dec 2012 12:17:59 -0800 Subject: [PATCH 0214/2239] bugfix: accessing ngx.var.VARIABLE allocated tempory memory buffers in the request memory bool, which could lead to unnecessarily large memory footprint. not it allocates such bufferes via Lua GC. --- src/ngx_http_lua_variable.c | 12 ++---------- t/045-ngx-var.t | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index adbd9f36cb..4f205961d6 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -99,10 +99,7 @@ ngx_http_lua_var_get(lua_State *L) p = (u_char *) luaL_checklstring(L, -1, &len); - lowcase = ngx_palloc(r->pool, len); - if (lowcase == NULL) { - return luaL_error(L, "memory allocation error"); - } + lowcase = lua_newuserdata(L, len); hash = ngx_hash_strlow(lowcase, p, len); @@ -158,12 +155,7 @@ ngx_http_lua_var_set(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); - lowcase = ngx_palloc(r->pool, len + 1); - if (lowcase == NULL) { - return luaL_error(L, "memory allocation error"); - } - - lowcase[len] = '\0'; + lowcase = lua_newuserdata(L, len); hash = ngx_hash_strlow(lowcase, p, len); diff --git a/t/045-ngx-var.t b/t/045-ngx-var.t index 0409f471cd..a5d52a0cfa 100644 --- a/t/045-ngx-var.t +++ b/t/045-ngx-var.t @@ -88,3 +88,18 @@ X-My-Host: foo foo --- SKIP + + +=== TEST 5: variable name is caseless +--- config + location = /test { + set $Var 32; + content_by_lua ' + ngx.say("value: ", ngx.var.VAR) + '; + } +--- request +GET /test +--- response_body +value: 32 + From 6e162fd013f56e044670eeb14aba001420f481fa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Dec 2012 12:20:40 -0800 Subject: [PATCH 0215/2239] minor coding style fixes in ngx_http_lua_variable.c. --- src/ngx_http_lua_variable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_variable.c b/src/ngx_http_lua_variable.c index 4f205961d6..edb5d49adb 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -189,7 +189,7 @@ ngx_http_lua_var_set(lua_State *L) default: msg = lua_pushfstring(L, "string, number, or nil expected, " - "but got %s", lua_typename(L, value_type)); + "but got %s", lua_typename(L, value_type)); return luaL_argerror(L, 1, msg); } @@ -260,7 +260,7 @@ ngx_http_lua_var_set(lua_State *L) } return luaL_error(L, "variable \"%s\" cannot be assigned a value", - lowcase); + lowcase); } /* variable not found */ From b802870d70398de85420da93d1b35ee65634e613 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 25 Dec 2012 21:51:53 -0800 Subject: [PATCH 0216/2239] docs: declared compatibility with nginx 1.2.6; also bumped version to 0.7.10. --- README | 6 +++--- README.markdown | 4 ++-- doc/HttpLuaModule.wiki | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index 0659eb793f..c248c1cbeb 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.9 - () released on 22 + This document describes ngx_lua v0.7.10 + () released on 25 December 2012. Synopsis @@ -5519,7 +5519,7 @@ Nginx Compatibility * 1.3.x (last tested: 1.3.7) - * 1.2.x (last tested: 1.2.4) + * 1.2.x (last tested: 1.2.6) * 1.1.x (last tested: 1.1.5) diff --git a/README.markdown b/README.markdown index 48753f8f97..b08d071c3b 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.9](https://github.com/chaoslawful/lua-nginx-module/tags) released on 22 December 2012. +This document describes ngx_lua [v0.7.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 25 December 2012. Synopsis ======== @@ -4862,7 +4862,7 @@ Nginx Compatibility The module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.7) -* 1.2.x (last tested: 1.2.4) +* 1.2.x (last tested: 1.2.6) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 18a94ecc7e..52f8994aed 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.9] released on 22 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.10] released on 25 December 2012. = Synopsis = @@ -4697,7 +4697,7 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k The module is compatible with the following versions of Nginx: * 1.3.x (last tested: 1.3.7) -* 1.2.x (last tested: 1.2.4) +* 1.2.x (last tested: 1.2.6) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) * 0.9.x (last tested: 0.9.4) From a78ee756108e9cf3c4c9e0cfc979045ca7d75ce6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 26 Dec 2012 17:03:53 -0800 Subject: [PATCH 0217/2239] bugfix: removed the unnecessary dot from the "config" file. thanks Rafael Souza for reporting this regression. --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index c2d2fa166b..ca15433fa4 100644 --- a/config +++ b/config @@ -137,7 +137,7 @@ END fi . auto/feature fi -. + if [ $ngx_found = no ]; then # Gentoo with LuaJIT-2.0 ngx_feature="LuaJIT library in /usr/" From d3c0f25469261518f3bb8c06b720bdb8eb13b9da Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 26 Dec 2012 17:15:57 -0800 Subject: [PATCH 0218/2239] docs: fixed a typo in the Lua code sample for ngx.re.gmatch (we forgot to add "do" there). thanks Guo Yin for reporting this issue. --- README | 2 +- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index c248c1cbeb..ca8ba3fc13 100644 --- a/README +++ b/README @@ -3637,7 +3637,7 @@ Nginx API for Lua More often we just put it into a Lua "for" loop: - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do ngx.say(m[0]) ngx.say(m[1]) end diff --git a/README.markdown b/README.markdown index b08d071c3b..81a73f2031 100644 --- a/README.markdown +++ b/README.markdown @@ -3351,7 +3351,7 @@ Here is a small example to demonstrate its basic usage: More often we just put it into a Lua `for` loop: - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do ngx.say(m[0]) ngx.say(m[1]) end diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 52f8994aed..1070ccc534 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3237,7 +3237,7 @@ Here is a small example to demonstrate its basic usage: More often we just put it into a Lua for loop: - for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") + for m in ngx.re.gmatch("hello, world!", "([a-z]+)", "i") do ngx.say(m[0]) ngx.say(m[1]) end From 58e14a62f53c6f2bcd784e5a1f3ea8f12649f741 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 27 Dec 2012 17:37:11 -0800 Subject: [PATCH 0219/2239] bumped version to 0.7.11. --- README | 10 +++++----- README.markdown | 8 ++++---- doc/HttpLuaModule.wiki | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README b/README index ca8ba3fc13..ce292cd04a 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.10 - () released on 25 + This document describes ngx_lua v0.7.11 + () released on 27 December 2012. Synopsis @@ -5560,9 +5560,9 @@ Installation Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.4.tar.gz' - tar -xzvf nginx-1.2.4.tar.gz - cd nginx-1.2.4/ + wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' + tar -xzvf nginx-1.2.6.tar.gz + cd nginx-1.2.6/ # 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 81a73f2031..66b72168a2 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.10](https://github.com/chaoslawful/lua-nginx-module/tags) released on 25 December 2012. +This document describes ngx_lua [v0.7.11](https://github.com/chaoslawful/lua-nginx-module/tags) released on 27 December 2012. Synopsis ======== @@ -4888,9 +4888,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.4.tar.gz' - tar -xzvf nginx-1.2.4.tar.gz - cd nginx-1.2.4/ + wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' + tar -xzvf nginx-1.2.6.tar.gz + cd nginx-1.2.6/ # 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 1070ccc534..71804a7f97 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.10] released on 25 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.11] released on 27 December 2012. = Synopsis = @@ -4721,9 +4721,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.2.4.tar.gz' - tar -xzvf nginx-1.2.4.tar.gz - cd nginx-1.2.4/ + wget 'http://nginx.org/download/nginx-1.2.6.tar.gz' + tar -xzvf nginx-1.2.6.tar.gz + cd nginx-1.2.6/ # tell nginx's build system where to find LuaJIT: export LUAJIT_LIB=/path/to/luajit/lib From d3280ab61bdfbedbf7408efcac3ed30afff127b6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 27 Dec 2012 20:41:07 -0800 Subject: [PATCH 0220/2239] docs: typo in the code sample for tcpsock:receiveuntil. thanks Yecheng Fu for the patch in github pull #196. --- README | 2 +- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index ce292cd04a..54e58ddd59 100644 --- a/README +++ b/README @@ -4473,7 +4473,7 @@ Nginx API for Lua local reader = sock:receiveuntil("\r\n--abcedhb") - while true then + while true do local data, err, partial = reader(4) if not data then if err then diff --git a/README.markdown b/README.markdown index 66b72168a2..b54f22af6a 100644 --- a/README.markdown +++ b/README.markdown @@ -4025,7 +4025,7 @@ The iterator function behaves differently (i.e., like a real iterator) when it i local reader = sock:receiveuntil("\r\n--abcedhb") - while true then + while true do local data, err, partial = reader(4) if not data then if err then diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 71804a7f97..91b96a0fe0 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3888,7 +3888,7 @@ The iterator function behaves differently (i.e., like a real iterator) when it i local reader = sock:receiveuntil("\r\n--abcedhb") - while true then + while true do local data, err, partial = reader(4) if not data then if err then From 9354740483651d25735113763f5534ffcd3668ab Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 28 Dec 2012 11:58:16 -0800 Subject: [PATCH 0221/2239] bugfix: ngx.decode_args() might modify (read-only) Lua strings in-place, which could lead to bad Lua string values. thanks Xu Jian for the report and Kindy Lin for the patch. --- src/ngx_http_lua_string.c | 9 +++-- t/030-uri-args.t | 80 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 51b8657277..747ceb2d2d 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -593,7 +593,7 @@ static int ngx_http_lua_ngx_decode_args(lua_State *L) { ngx_http_request_t *r; u_char *buf; - u_char *last; + u_char *tmp; size_t len = 0; int n; int max; @@ -623,11 +623,12 @@ ngx_http_lua_ngx_decode_args(lua_State *L) { return luaL_error(L, "no request object found"); } - lua_createtable(L, 0, 4); + tmp = lua_newuserdata(L, len); + ngx_memcpy(tmp, buf, len); - last = buf + len; + lua_createtable(L, 0, 4); - return ngx_http_lua_parse_args(r, L, buf, last, max); + return ngx_http_lua_parse_args(r, L, tmp, tmp + len, max); } diff --git a/t/030-uri-args.t b/t/030-uri-args.t index b614ae8761..7f99572b1f 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 + 5); +plan tests => repeat_each() * (blocks() * 2 + 7); no_root_location(); @@ -1111,3 +1111,81 @@ GET /lua a = bar b = foo + + +=== TEST 48: ngx.decode_args should not modify lua strings in place +--- config + location /lua { + content_by_lua ' + local s = "f+f=bar&B=foo" + args = ngx.decode_args(s) + for k, v in pairs(args) do + ngx.say("key: ", k) + end + ngx.say("s = ", s) + '; + } +--- request +GET /lua +--- response_body +key: f f +key: B +s = f+f=bar&B=foo +--- no_error_log +[error] + + + +=== TEST 49: ngx.decode_args should not modify lua strings in place (sample from Xu Jian) +--- config + lua_need_request_body on; + location /t { + content_by_lua ' + function split(s, delimiter) + local result = {} + local from = 1 + local delim_from, delim_to = string.find(s, delimiter, from) + while delim_from do + table.insert(result, string.sub(s, from, delim_from - 1)) + from = delim_to + 1 + delim_from, delim_to = string.find(s, delimiter, from) + end + table.insert(result, string.sub(s, from)) + return result + end + + local post_data = ngx.req.get_body_data() + + local commands = split(post_data, "||") + for _, command in pairs(commands) do + --command = ngx.unescape_uri(command) + local request_args = ngx.decode_args(command, 0) + for key, value in pairs(request_args) do + ngx.say(key, ": ", value) + end + ngx.say(" ===============") + end + '; + } +--- request +POST /t +method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852||method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852||method=zadd&key=User%3A1227713%3Alikes%3Atwitters&arg1=1356514698&arg2=780984852 +--- response_body +arg2: 780984852 +method: zadd +key: User:1227713:likes:twitters +arg1: 1356514698 + =============== +arg2: 780984852 +method: zadd +key: User:1227713:likes:twitters +arg1: 1356514698 + =============== +arg2: 780984852 +method: zadd +key: User:1227713:likes:twitters +arg1: 1356514698 + =============== +--- no_error_log +[error] + From 87d109fce31b139a775f57107a0b49cce30c7001 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 29 Dec 2012 21:29:42 -0800 Subject: [PATCH 0222/2239] docs: bumped version to 0.7.12. --- README | 4 ++-- README.markdown | 2 +- doc/HttpLuaModule.wiki | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 54e58ddd59..47cca93a94 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.11 - () released on 27 + This document describes ngx_lua v0.7.12 + () released on 29 December 2012. Synopsis diff --git a/README.markdown b/README.markdown index b54f22af6a..000b8d6402 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.11](https://github.com/chaoslawful/lua-nginx-module/tags) released on 27 December 2012. +This document describes ngx_lua [v0.7.12](https://github.com/chaoslawful/lua-nginx-module/tags) released on 29 December 2012. Synopsis ======== diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 91b96a0fe0..47f2010189 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.11] released on 27 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.12] released on 29 December 2012. = Synopsis = From e059eac04590ffaeec4a22c42cac2bdc7f2f0636 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 2 Jan 2013 12:00:11 -0800 Subject: [PATCH 0223/2239] bugfix: using a key with underscores in ngx.header.KEY resulted in Lua string storage corruption. thanks rkearsley for reporting this as github issue #199. --- src/ngx_http_lua_headers.c | 21 ++++++++++----------- t/016-resp-header.t | 32 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 0ea54eda97..99a9d41fe0 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -197,10 +197,20 @@ ngx_http_lua_ngx_header_set(lua_State *L) dd("key: %.*s, len %d", (int) len, p, (int) len); + key.data = ngx_palloc(r->pool, len + 1); + if (key.data == NULL) { + return luaL_error(L, "out of memory"); + } + + ngx_memcpy(key.data, p, len); + key.data[len] = '\0'; + key.len = len; + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers) { /* replace "_" with "-" */ + p = key.data; for (i = 0; i < len; i++) { if (p[i] == '_') { p[i] = '-'; @@ -208,17 +218,6 @@ ngx_http_lua_ngx_header_set(lua_State *L) } } - key.data = ngx_palloc(r->pool, len + 1); - if (key.data == NULL) { - return luaL_error(L, "out of memory"); - } - - ngx_memcpy(key.data, p, len); - - key.data[len] = '\0'; - - key.len = len; - if (!ctx->headers_set) { rc = ngx_http_set_content_type(r); if (rc != NGX_OK) { diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 7a1a5efdf1..111b4c3255 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 - 1); +plan tests => repeat_each() * (blocks() * 3); #no_diff(); no_long_string(); @@ -823,3 +823,33 @@ nil Hello Hello + + +=== TEST 42: github issue #199: underscores in lua variables +--- config + location /read { + content_by_lua ' + ngx.header.content_type = "text/my-plain" + + local results = {} + results.something = "hello" + results.content_type = "anything" + results.somehing_else = "hi" + + for k, v in pairs(results) do + ngx.say(k .. ": " .. v) + end + '; + } +--- request +GET /read +--- response_headers +Content-Type: text/my-plain + +--- response_body +somehing_else: hi +something: hello +content_type: anything +--- no_error_log +[error] + From 93e0e2929f31008fcb073e57ac20b7fe3be72ae4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 3 Jan 2013 16:55:34 -0800 Subject: [PATCH 0224/2239] docs: bumped version to 0.7.13. --- README | 10 +++++----- README.markdown | 6 +++--- doc/HttpLuaModule.wiki | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README b/README index 47cca93a94..29778ffb3d 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.12 - () released on 29 - December 2012. + This document describes ngx_lua v0.7.13 + () released on 3 + January 2013. Synopsis # set search paths for pure Lua external libraries (';;' is the default path): @@ -5740,10 +5740,10 @@ Test Suite Copyright and License This module is licensed under the BSD license. - Copyright (C) 2009-2012, by Xiaozhe Wang (chaoslawful) + Copyright (C) 2009-2013, by Xiaozhe Wang (chaoslawful) . - Copyright (C) 2009-2012, by Yichun "agentzh" Zhang (章亦春) + Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) . All rights reserved. diff --git a/README.markdown b/README.markdown index 000b8d6402..c78f885a7c 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.12](https://github.com/chaoslawful/lua-nginx-module/tags) released on 29 December 2012. +This document describes ngx_lua [v0.7.13](https://github.com/chaoslawful/lua-nginx-module/tags) released on 3 January 2013. Synopsis ======== @@ -5029,9 +5029,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2012, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2013, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2012, by Yichun "agentzh" Zhang (章亦春) . +Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) . All rights reserved. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 47f2010189..f02c78385a 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.12] released on 29 December 2012. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.13] released on 3 January 2013. = Synopsis = @@ -4851,9 +4851,9 @@ filtering chain determines the final output. The correct adding order is: This module is licensed under the BSD license. -Copyright (C) 2009-2012, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2013, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2012, by Yichun "agentzh" Zhang (章亦春) . +Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) . All rights reserved. From 4b1adde524ecd0fe4a98cea5006a19fa9841623e Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Mon, 7 Jan 2013 00:03:02 +0400 Subject: [PATCH 0225/2239] OpenBSD-5.2 --- config | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/config b/config index ca15433fa4..2117c31132 100644 --- a/config +++ b/config @@ -67,7 +67,19 @@ END . auto/feature if [ $ngx_found = no ]; then - # OpenBSD + # OpenBSD-5.2 + ngx_feature="Lua library in /usr/local/" + ngx_feature_path="/usr/local/include/lua-5.1" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -llua -lm" + else + ngx_feature_libs="-L/usr/local/lib -llua5.1 -lm" + fi + . auto/feature + fi + + if [ $ngx_found = no ]; then + # OpenBSD < 5.2 ngx_feature="Lua library in /usr/local/" ngx_feature_path="/usr/local/include" if [ $NGX_RPATH = YES ]; then From f6e62d56317c9a72e43207207770a340ddb334a4 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 8 Jan 2013 18:48:59 -0800 Subject: [PATCH 0226/2239] bugfix: in body_filter_by_lua, the "eof" flag (i.e., ngx.arg[2]) was not set in subrequests. --- src/ngx_http_lua_bodyfilterby.c | 2 +- t/014-bugs.t | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 40e0e927ec..92ce2fedb1 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -385,7 +385,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L) /* asking for the eof argument */ for (cl = in; cl; cl = cl->next) { - if (cl->buf->last_buf) { + if (cl->buf->last_buf || cl->buf->last_in_chain) { lua_pushboolean(L, 1); return 1; } diff --git a/t/014-bugs.t b/t/014-bugs.t index 4b87103832..e908210cac 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 + 21); +plan tests => repeat_each() * (blocks() * 2 + 22); our $HtmlDir = html_dir; #warn $html_dir; @@ -724,3 +724,29 @@ Content-Type: application/json; charset=utf-8 --- error_log upstream prematurely closed connection while reading response header from upstream + + +=== TEST 33: last_in_chain is set properly in subrequests +--- config + location = /sub { + echo hello; + body_filter_by_lua ' + local eof = ngx.arg[2] + if eof then + print("eof found in body stream") + end + '; + } + + location = /main { + echo_location /sub; + } + +--- request + GET /main +--- response_body +hello +--- log_level: notice +--- error_log +eof found in body stream + From 1a52a5819def1f056a3c137a604f7a3398c812ef Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 11 Jan 2013 15:34:35 -0800 Subject: [PATCH 0227/2239] feature: setting ngx.header.HEADER after sending out the response headers now only produced an error message in the nginx error logs and does not throw out a Lua exception. this should be handy for Lua development. thanks Matthieu Tourne for suggesting this. --- src/ngx_http_lua_headers.c | 6 ++++-- t/016-resp-header.t | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 99a9d41fe0..9f593153fd 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -188,8 +188,10 @@ ngx_http_lua_ngx_header_set(lua_State *L) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx->headers_sent) { - return luaL_error(L, "attempt to set ngx.header.HEADER after " - "sending out response headers"); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to " + "set ngx.header.HEADER after sending out " + "response headers"); + return 0; } /* we skip the first argument that is the table */ diff --git a/t/016-resp-header.t b/t/016-resp-header.t index 111b4c3255..b8fe723bbd 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -9,7 +9,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); no_long_string(); @@ -274,7 +274,8 @@ Fooy: cony1, cony2 } --- request GET /lua ---- ignore_response +--- response_body chop +hello --- error_log attempt to set ngx.header.HEADER after sending out response headers --- no_error_log eval From 7786f978e0f37918fae45848a9626bf1829f0925 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 11:08:26 -0800 Subject: [PATCH 0228/2239] bugfix: because of the recent API behaviour changes in nginx 1.2.6+ and 1.3.9+, the "http request count is zero" alert might happen when ngx.req.read_body() was called to read the request body and nginx failed to send out the "100 Continue" (short) response (like client connection early abortion and etc). thanks stonehuzhan for reporting this issue. --- src/ngx_http_lua_req_body.c | 8 ++++++++ t/044-req-body.t | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 047545de7d..169e4a3516 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -112,12 +112,20 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) rc = ngx_http_read_client_request_body(r, ngx_http_lua_req_body_post_read); +#if (nginx_version < 1002006) || \ + (nginx_version >= 1003000 && nginx_version < 1003009) r->main->count--; +#endif if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to read request body"); } +#if (nginx_version >= 1002006 && nginx_version < 1003000) || \ + nginx_version >= 1003009 + r->main->count--; +#endif + if (rc == NGX_AGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua read buffered request body requires I/O interruptions"); diff --git a/t/044-req-body.t b/t/044-req-body.t index 1e167d70ef..d10d6ed0cf 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -33,6 +33,7 @@ hello, world hello, world --- no_error_log [error] +[alert] @@ -1314,3 +1315,30 @@ failed to get req socket: request body already exists --- no_error_log a client request body is buffered to a temporary file + + +=== TEST 41: failed to write 100 continue +--- config + location = /test { + content_by_lua ' + ngx.sleep(0.01) + ngx.req.read_body() + ngx.say(ngx.var.request_body) + '; + } +--- request +POST /test +hello, world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +hello, world +--- error_log +failed to read request body +--- no_error_log +[alert] +http finalize request: 500, "/test?" a:1, c:0 + From f71e4700f156da3de2fcfe3eaa0d9ca30a842e7b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 11:25:50 -0800 Subject: [PATCH 0229/2239] fixed a failing test case in normal testing mode. --- t/044-req-body.t | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/t/044-req-body.t b/t/044-req-body.t index d10d6ed0cf..34aea9afd7 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 5); +plan tests => repeat_each() * (blocks() * 4 + 4); #no_diff(); no_long_string(); @@ -1336,8 +1336,6 @@ Expect: 100-Continue --- wait: 0.1 --- ignore_response hello, world ---- error_log -failed to read request body --- no_error_log [alert] http finalize request: 500, "/test?" a:1, c:0 From fec300b7360d3da7f1244d22d73fcbc5791775e0 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 11:59:57 -0800 Subject: [PATCH 0230/2239] bugfix: we did not get the request reference counter right when lua_need_request_body was turned on and nginx versions older than 1.2.6 or 1.2.9 were used. --- src/ngx_http_lua_accessby.c | 5 +++++ src/ngx_http_lua_contentby.c | 4 ++++ src/ngx_http_lua_rewriteby.c | 5 +++++ t/010-request_body.t | 30 ++++++++++++++++++++++++++++-- t/023-rewrite/request_body.t | 33 ++++++++++++++++++++++++++++++--- t/024-access/request_body.t | 32 +++++++++++++++++++++++++++++--- 6 files changed, 101 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 710dba3024..67290dc2c3 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -114,6 +114,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { +#if (nginx_version < 1002006) || \ + (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif + return rc; } diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 3239382770..300935898b 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -179,6 +179,10 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) ngx_http_lua_content_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { +#if (nginx_version < 1002006) || \ + (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif return rc; } diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 82750a28b0..e13c58651c 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -116,6 +116,11 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { +#if (nginx_version < 1002006) || \ + (nginx_version >= 1003000 && nginx_version < 1003009) + r->main->count--; +#endif + return rc; } diff --git a/t/010-request_body.t b/t/010-request_body.t index f47440fe23..9a13ebb0da 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -6,9 +6,9 @@ use Test::Nginx::Socket; #master_process_enabled(1); log_level('debug'); # to ensure any log-level can be outputed -repeat_each(1); +repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); #no_long_string(); @@ -248,3 +248,29 @@ hi --- response_body 2 + + +=== TEST 12: Expect: 100-Continue +--- config + location /echo_body { + lua_need_request_body on; + content_by_lua ' + ngx.print(ngx.var.request_body or "nil") + '; + } +--- request +POST /echo_body +hello world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] +http finalize request: 500, "/echo_body?" a:1, c:2 +http finalize request: 500, "/echo_body?" a:1, c:0 +--- log_level: debug + diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index 517c88386d..1a37f87cd6 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -1,4 +1,4 @@ -# vim:set ft=perl ts=4 sw=4 et fdm=marker: +# vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; use Test::Nginx::Socket; @@ -6,9 +6,9 @@ use Test::Nginx::Socket; #master_process_enabled(1); log_level('debug'); # to ensure any log-level can be outputed -repeat_each(1); +repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); #no_long_string(); @@ -148,3 +148,30 @@ world\x03\x04\xff" --- response_body eval "nil" + + +=== TEST 8: Expect: 100-Continue +--- config + location /echo_body { + lua_need_request_body on; + rewrite_by_lua ' + ngx.print(ngx.var.request_body or "nil") + ngx.exit(200) + '; + } +--- request +POST /echo_body +hello world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] +http finalize request: 500, "/echo_body?" a:1, c:2 +http finalize request: 500, "/echo_body?" a:1, c:0 +--- log_level: debug + diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 31ecfb2ac0..3413e47b31 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -1,4 +1,4 @@ -# vim:set ft=perl ts=4 sw=4 et fdm=marker: +# vim:set ft= ts=4 sw=4 et fdm=marker: use lib 'lib'; use Test::Nginx::Socket; @@ -6,9 +6,9 @@ use Test::Nginx::Socket; #master_process_enabled(1); log_level('debug'); # to ensure any log-level can be outputed -repeat_each(1); +repeat_each(2); -plan tests => repeat_each() * (blocks() * 2); +plan tests => repeat_each() * (blocks() * 2 + 2); #no_diff(); #no_long_string(); @@ -148,3 +148,29 @@ world\x03\x04\xff" --- response_body eval "nil" + +=== TEST 8: Expect: 100-Continue +--- config + location /echo_body { + lua_need_request_body on; + access_by_lua ' + ngx.print(ngx.var.request_body or "nil") + ngx.exit(200) + '; + } +--- request +POST /echo_body +hello world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +--- no_error_log +[error] +[alert] +http finalize request: 500, "/echo_body?" a:1, c:2 +http finalize request: 500, "/echo_body?" a:1, c:0 +--- log_level: debug + From 6398a904855e0eb5439508c72b5432991ead0fa9 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 12:01:02 -0800 Subject: [PATCH 0231/2239] updated tests to reflect recent changes in the DNS settings for my agentzh.org domain. --- 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 747b462b0e..5b1a9f8501 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("agentzh.org", port) + local ok, err = sock:connect("direct.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 47eba4f95d..dbef649513 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("agentzh.org", port) + local ok, err = sock:connect("direct.agentzh.org", port) if not ok then ngx.say("failed to connect: ", err) return From 00bd9a4c35bdc8ddf645173316cf4c4c8b7b1912 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 12:02:03 -0800 Subject: [PATCH 0232/2239] added (passing) tests for using ngx.req.read_body in the "rewrite" and "access" phases when nginx fails to send the "100 Continue" response. --- t/023-rewrite/req-body.t | 26 ++++++++++++++++++++++++++ t/024-access/req-body.t | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index abb9a2a210..1f95e0fef6 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -101,3 +101,29 @@ hello, world hello, world sub: foo + + +=== TEST 5: failed to write 100 continue +--- config + location = /test { + rewrite_by_lua ' + ngx.sleep(0.01) + ngx.req.read_body() + ngx.say(ngx.var.request_body) + ngx.exit(200) + '; + } +--- request +POST /test +hello, world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +hello, world +--- no_error_log +[alert] +http finalize request: 500, "/test?" a:1, c:0 + diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index 816f0ed85c..e1d42814e5 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -101,3 +101,29 @@ hello, world hello, world sub: foo + + +=== TEST 5: failed to write 100 continue +--- config + location = /test { + access_by_lua ' + ngx.sleep(0.01) + ngx.req.read_body() + ngx.say(ngx.var.request_body) + ngx.exit(200) + '; + } +--- request +POST /test +hello, world +--- more_headers +Expect: 100-Continue +--- abort +--- timeout: 0.001 +--- wait: 0.1 +--- ignore_response +hello, world +--- no_error_log +[alert] +http finalize request: 500, "/test?" a:1, c:0 + From b9ac4139d95921894b4a0206dceef66512d6645d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 16 Jan 2013 12:32:01 -0800 Subject: [PATCH 0233/2239] refactor: when the nginx core fails to send the "100 Continue" response in case of the "Expect: 100-continue" request header (or just running out of memory), ngx.req.read_body() will no longer throw out a "failed to read request body" Lua error but will just terminate the current request and returns the 500 error page immediately, just as what the Nginx core does in this case. --- src/ngx_http_lua_req_body.c | 9 ++++++++- t/023-rewrite/req-body.t | 3 ++- t/024-access/req-body.t | 3 ++- t/044-req-body.t | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 169e4a3516..56f449c3ae 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -118,7 +118,14 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) #endif if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to read request body"); + ctx->exit_code = rc; + ctx->exited = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http read client request body returned error code %i, " + "exitting now", rc); + + return lua_yield(L, 0); } #if (nginx_version >= 1002006 && nginx_version < 1003000) || \ diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index 1f95e0fef6..f35bcaef0c 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -8,7 +8,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(); @@ -125,5 +125,6 @@ Expect: 100-Continue hello, world --- no_error_log [alert] +[error] http finalize request: 500, "/test?" a:1, c:0 diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index e1d42814e5..3882cc7bba 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -8,7 +8,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(); @@ -125,5 +125,6 @@ Expect: 100-Continue hello, world --- no_error_log [alert] +[error] http finalize request: 500, "/test?" a:1, c:0 diff --git a/t/044-req-body.t b/t/044-req-body.t index 34aea9afd7..333a40c7be 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 4); +plan tests => repeat_each() * (blocks() * 4 + 5); #no_diff(); no_long_string(); @@ -1338,5 +1338,6 @@ Expect: 100-Continue hello, world --- no_error_log [alert] +[error] http finalize request: 500, "/test?" a:1, c:0 From bc53e62bca728bfaa269c51707f947e6643b0e67 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 21 Jan 2013 15:41:04 -0800 Subject: [PATCH 0234/2239] fixed those recently-added tests for 100 continue that may fail expectedly. --- t/010-request_body.t | 3 --- t/023-rewrite/req-body.t | 5 ----- t/023-rewrite/request_body.t | 3 --- t/024-access/req-body.t | 5 ----- t/024-access/request_body.t | 4 +--- t/044-req-body.t | 5 ----- 6 files changed, 1 insertion(+), 24 deletions(-) diff --git a/t/010-request_body.t b/t/010-request_body.t index 9a13ebb0da..b14cf59736 100644 --- a/t/010-request_body.t +++ b/t/010-request_body.t @@ -263,9 +263,6 @@ POST /echo_body hello world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response --- no_error_log [error] diff --git a/t/023-rewrite/req-body.t b/t/023-rewrite/req-body.t index f35bcaef0c..981e723443 100644 --- a/t/023-rewrite/req-body.t +++ b/t/023-rewrite/req-body.t @@ -107,7 +107,6 @@ sub: foo --- config location = /test { rewrite_by_lua ' - ngx.sleep(0.01) ngx.req.read_body() ngx.say(ngx.var.request_body) ngx.exit(200) @@ -118,11 +117,7 @@ POST /test hello, world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response -hello, world --- no_error_log [alert] [error] diff --git a/t/023-rewrite/request_body.t b/t/023-rewrite/request_body.t index 1a37f87cd6..f46dd530e2 100644 --- a/t/023-rewrite/request_body.t +++ b/t/023-rewrite/request_body.t @@ -164,9 +164,6 @@ POST /echo_body hello world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response --- no_error_log [error] diff --git a/t/024-access/req-body.t b/t/024-access/req-body.t index 3882cc7bba..8ab6452447 100644 --- a/t/024-access/req-body.t +++ b/t/024-access/req-body.t @@ -107,7 +107,6 @@ sub: foo --- config location = /test { access_by_lua ' - ngx.sleep(0.01) ngx.req.read_body() ngx.say(ngx.var.request_body) ngx.exit(200) @@ -118,11 +117,7 @@ POST /test hello, world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response -hello, world --- no_error_log [alert] [error] diff --git a/t/024-access/request_body.t b/t/024-access/request_body.t index 3413e47b31..46e4109113 100644 --- a/t/024-access/request_body.t +++ b/t/024-access/request_body.t @@ -149,6 +149,7 @@ world\x03\x04\xff" "nil" + === TEST 8: Expect: 100-Continue --- config location /echo_body { @@ -163,9 +164,6 @@ POST /echo_body hello world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response --- no_error_log [error] diff --git a/t/044-req-body.t b/t/044-req-body.t index 333a40c7be..7f3a96eb7b 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -1321,7 +1321,6 @@ a client request body is buffered to a temporary file --- config location = /test { content_by_lua ' - ngx.sleep(0.01) ngx.req.read_body() ngx.say(ngx.var.request_body) '; @@ -1331,11 +1330,7 @@ POST /test hello, world --- more_headers Expect: 100-Continue ---- abort ---- timeout: 0.001 ---- wait: 0.1 --- ignore_response -hello, world --- no_error_log [alert] [error] From ab02c1203a4d90f18e572812b26ba982aa08c1a3 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 22 Jan 2013 15:32:51 -0800 Subject: [PATCH 0235/2239] bugfix: failed to compile with the SPDY patch 58_1.3.11 because that patch removed the field from the Nginx core. thanks Chris Lea for reporting this in github issue \#203. --- src/ngx_http_lua_socket_tcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index c46b7ccdc6..a4148ce0e9 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -441,8 +441,6 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->connect_timeout = u->conf->connect_timeout; } - r->connection->single_connection = 0; - rc = ngx_http_lua_get_keepalive_peer(r, L, key_index, u); if (rc == NGX_OK) { From 2603780dd4f8598e5fa6fe5434d08fb290545dff Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 22 Jan 2013 16:14:41 -0800 Subject: [PATCH 0236/2239] added a test case for a segfault in the nginx core when using ngx_poll_module + ngx_resolver together. --- t/014-bugs.t | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/t/014-bugs.t b/t/014-bugs.t index e908210cac..cf16849340 100644 --- a/t/014-bugs.t +++ b/t/014-bugs.t @@ -750,3 +750,24 @@ hello --- error_log eof found in body stream + + +=== TEST 34: testing a segfault when using ngx_poll_module + ngx_resolver +See more details here: http://mailman.nginx.org/pipermail/nginx-devel/2013-January/003275.html +--- config + location /t { + set $myserver nginx.org; + proxy_pass http://$myserver/; + resolver 127.0.0.1; + } +--- request + GET /t +--- ignore_response +--- abort +--- timeout: 0.3 +--- log_level: notice +--- no_error_log +[alert] +--- error_log eval +qr/recv\(\) failed \(\d+: Connection refused\) while resolving/ + From 0d12003313607eac6848f9e542a25ffced8766d8 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Tue, 22 Jan 2013 17:52:06 -0800 Subject: [PATCH 0237/2239] tests: eliminated hitting Google's web servers (but we still make use of its public DNS servers). --- t/016-resp-header.t | 4 +-- t/022-redirect.t | 18 +++++----- t/023-rewrite/client-abort.t | 4 +-- t/023-rewrite/on-abort.t | 2 +- t/023-rewrite/tcp-socket-timeout.t | 10 +++--- t/023-rewrite/uthread-exit.t | 55 ++++++++++++++++++++---------- t/024-access/client-abort.t | 4 +-- t/024-access/uthread-exit.t | 36 +++++++++---------- t/030-uri-args.t | 4 +-- t/058-tcp-socket.t | 2 +- t/065-tcp-socket-timeout.t | 10 +++--- t/094-uthread-exit.t | 36 +++++++++---------- t/100-client-abort.t | 4 +-- 13 files changed, 104 insertions(+), 85 deletions(-) diff --git a/t/016-resp-header.t b/t/016-resp-header.t index b8fe723bbd..e81a87da45 100644 --- a/t/016-resp-header.t +++ b/t/016-resp-header.t @@ -74,13 +74,13 @@ Hel location /read { content_by_lua ' ngx.status = 302; - ngx.header["Location"] = "http://google.com/foo"; + ngx.header["Location"] = "http://agentzh.org/foo"; '; } --- request GET /read --- response_headers -Location: http://google.com/foo +Location: http://agentzh.org/foo --- response_body --- error_code: 302 diff --git a/t/022-redirect.t b/t/022-redirect.t index 261108e038..2bc98e65e0 100644 --- a/t/022-redirect.t +++ b/t/022-redirect.t @@ -23,14 +23,14 @@ __DATA__ --- config location /read { content_by_lua ' - ngx.redirect("http://google.com/foo"); + ngx.redirect("http://agentzh.org/foo"); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://google.com/foo +Location: http://agentzh.org/foo --- response_body_like: 302 Found --- error_code: 302 @@ -40,14 +40,14 @@ Location: http://google.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://google.com/foo", ngx.HTTP_MOVED_TEMPORARILY); + ngx.redirect("http://agentzh.org/foo", ngx.HTTP_MOVED_TEMPORARILY); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://google.com/foo +Location: http://agentzh.org/foo --- response_body_like: 302 Found --- error_code: 302 @@ -57,14 +57,14 @@ Location: http://google.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://google.com/foo", ngx.HTTP_MOVED_PERMANENTLY); + ngx.redirect("http://agentzh.org/foo", ngx.HTTP_MOVED_PERMANENTLY); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://google.com/foo +Location: http://agentzh.org/foo --- response_body_like: 301 Moved Permanently --- error_code: 301 @@ -74,7 +74,7 @@ Location: http://google.com/foo --- config location /read { content_by_lua ' - ngx.redirect("http://google.com/foo", 404); + ngx.redirect("http://agentzh.org/foo", 404); ngx.say("hi") '; } @@ -131,14 +131,14 @@ GET /read --- config location /read { content_by_lua ' - ngx.redirect("http://google.com/foo?bar=3"); + ngx.redirect("http://agentzh.org/foo?bar=3"); ngx.say("hi") '; } --- request GET /read --- response_headers -Location: http://google.com/foo?bar=3 +Location: http://agentzh.org/foo?bar=3 --- response_body_like: 302 Found --- error_code: 302 diff --git a/t/023-rewrite/client-abort.t b/t/023-rewrite/client-abort.t index 87f916c99e..e7f1becd8e 100644 --- a/t/023-rewrite/client-abort.t +++ b/t/023-rewrite/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t diff --git a/t/023-rewrite/on-abort.t b/t/023-rewrite/on-abort.t index cf0c760624..3b04459608 100644 --- a/t/023-rewrite/on-abort.t +++ b/t/023-rewrite/on-abort.t @@ -365,7 +365,7 @@ delete thread 1 --- timeout: 0.2 --- abort ---- wait: 0.2 +--- wait: 0.3 --- ignore_response --- no_error_log [error] diff --git a/t/023-rewrite/tcp-socket-timeout.t b/t/023-rewrite/tcp-socket-timeout.t index f1affcc11c..b7b2b94114 100644 --- a/t/023-rewrite/tcp-socket-timeout.t +++ b/t/023-rewrite/tcp-socket-timeout.t @@ -42,7 +42,7 @@ __DATA__ location /t1 { rewrite_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -75,7 +75,7 @@ lua tcp socket connect timed out rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("www.google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -110,7 +110,7 @@ lua tcp socket connect timeout: 150 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("www.google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -145,7 +145,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("www.google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -181,7 +181,7 @@ lua tcp socket connect timeout: 102 rewrite_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("www.google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index 8cff1d1ebd..5f7d55157a 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -309,12 +309,12 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; resolver_timeout 12s; rewrite_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -322,7 +322,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 80) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -339,6 +339,14 @@ GET /lua global timers +F(ngx_resolve_start) { + println("resolver started") +} + +F(ngx_http_lua_socket_resolve_handler) { + println("resolver done") +} + F(ngx_http_free_request) { println("free request") } @@ -348,7 +356,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -356,7 +364,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -369,7 +377,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -383,10 +391,11 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolver started +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua tcp resolve cleanup delete timer 12000 @@ -408,12 +417,13 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; + #resolver 127.0.0.1; resolver_timeout 12s; rewrite_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -421,7 +431,7 @@ after ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() - local ok, err = sock:setpeername("www.google.com", 80) + local ok, err = sock:setpeername("agentzh.org", 80) if not ok then ngx.say("failed to connect: ", err) return @@ -438,6 +448,14 @@ GET /lua global timers +F(ngx_resolve_start) { + println("resolver started") +} + +F(ngx_http_lua_socket_resolve_handler) { + println("resolver done") +} + F(ngx_http_free_request) { println("free request") } @@ -447,7 +465,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -455,7 +473,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -468,7 +486,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -482,10 +500,11 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolver started +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua udp resolve cleanup delete timer 12000 diff --git a/t/024-access/client-abort.t b/t/024-access/client-abort.t index 6b7d542b73..d070346e5b 100644 --- a/t/024-access/client-abort.t +++ b/t/024-access/client-abort.t @@ -200,7 +200,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -241,7 +241,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index 099d23adad..bf604808c2 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -309,12 +309,12 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -322,7 +322,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 80) + local ok, err = sock:connect("agentzh.org", 80) if not ok then ngx.say("failed to connect: ", err) return @@ -348,7 +348,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -356,7 +356,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -369,7 +369,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -383,10 +383,10 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua tcp resolve cleanup delete timer 12000 @@ -408,12 +408,12 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; resolver_timeout 12s; access_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -421,7 +421,7 @@ after ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() - local ok, err = sock:setpeername("www.google.com", 80) + local ok, err = sock:setpeername("agentzh.org", 80) if not ok then ngx.say("failed to connect: ", err) return @@ -447,7 +447,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -455,7 +455,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -468,7 +468,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -482,10 +482,10 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua udp resolve cleanup delete timer 12000 diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 7f99572b1f..4595e1f404 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -357,7 +357,7 @@ done ngx.req.set_uri_args("hello") ngx.req.set_uri("/bar", true); '; - proxy_pass http://google.com:5678; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world @@ -496,7 +496,7 @@ HTTP/1.0 ca%20t=%25 ngx.req.set_uri("/bar", true); ngx.exit(503) '; - proxy_pass http://google.com:5678; + proxy_pass http://agentzh.org:12345; } --- request GET /foo?world diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index dbef649513..fd530b5c06 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -298,7 +298,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ location /test { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("google.com", 16787) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say("connect: ", ok, " ", err) local bytes diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index 17748706d5..09953e2d0e 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -47,7 +47,7 @@ __DATA__ location /t { content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -75,7 +75,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(150) - local ok, err = sock:connect("google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -103,7 +103,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(nil) - local ok, err = sock:connect("google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -131,7 +131,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(0) - local ok, err = sock:connect("google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return @@ -160,7 +160,7 @@ lua tcp socket connect timed out content_by_lua ' local sock = ngx.socket.tcp() sock:settimeout(-1) - local ok, err = sock:connect("google.com", 12345) + local ok, err = sock:connect("agentzh.org", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index fe8f5ee688..d576a07936 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -297,12 +297,12 @@ exiting the user thread === TEST 5: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.tcp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -310,7 +310,7 @@ exiting the user thread ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.tcp() - local ok, err = sock:connect("www.google.com", 80) + local ok, err = sock:connect("agentzh.org", 80) if not ok then ngx.say("failed to connect: ", err) return @@ -335,7 +335,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -343,7 +343,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -356,7 +356,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -370,10 +370,10 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua tcp resolve cleanup delete timer 12000 @@ -393,12 +393,12 @@ after === TEST 6: exit in user thread (entry thread is still pending on the DNS resolver for ngx.socket.udp) --- config location /lua { - resolver www.google.com; + resolver agentzh.org; resolver_timeout 12s; content_by_lua ' function f() ngx.say("hello in thread") - ngx.sleep(0.1) + ngx.sleep(0.001) ngx.exit(0) end @@ -406,7 +406,7 @@ after ngx.thread.spawn(f) ngx.say("after") local sock = ngx.socket.udp() - local ok, err = sock:setpeername("www.google.com", 80) + local ok, err = sock:setpeername("agentzh.org", 80) if not ok then ngx.say("failed to connect: ", err) return @@ -431,7 +431,7 @@ F(ngx_resolve_name) { } M(timer-add) { - if ($arg2 == 12000 || $arg2 == 100) { + if ($arg2 == 12000 || $arg2 == 1) { timers[$arg1] = $arg2 printf("add timer %d\n", $arg2) } @@ -439,7 +439,7 @@ M(timer-add) { M(timer-del) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("delete timer %d\n", tm) delete timers[$arg1] } @@ -452,7 +452,7 @@ M(timer-del) { M(timer-expire) { tm = timers[$arg1] - if (tm == 12000 || tm == 100) { + if (tm == 12000 || tm == 1) { printf("expire timer %d\n", timers[$arg1]) delete timers[$arg1] } @@ -466,10 +466,10 @@ _EOC_ --- stap_out create 2 in 1 spawn user thread 2 in 1 -add timer 100 -resolving www.google.com +add timer 1 +resolving agentzh.org add timer 12000 -expire timer 100 +expire timer 1 terminate 2: ok lua udp resolve cleanup delete timer 12000 diff --git a/t/100-client-abort.t b/t/100-client-abort.t index 5d8ad87430..f1ff0655a9 100644 --- a/t/100-client-abort.t +++ b/t/100-client-abort.t @@ -196,7 +196,7 @@ bad things happen location = /sub { proxy_ignore_client_abort on; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } location = /sleep { @@ -237,7 +237,7 @@ client prematurely closed connection location = /sub { proxy_ignore_client_abort off; - proxy_pass http://www.google.com:1234/; + proxy_pass http://agentzh.org:12345/; } --- request GET /t From 329907fd0549813ad556421ad9684d87c2674c76 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 12:28:20 -0800 Subject: [PATCH 0238/2239] tests: stopped hitting Google's open DNS server's 12345 port. --- t/023-rewrite/uthread-exit.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/023-rewrite/uthread-exit.t b/t/023-rewrite/uthread-exit.t index 5f7d55157a..c270da1176 100644 --- a/t/023-rewrite/uthread-exit.t +++ b/t/023-rewrite/uthread-exit.t @@ -538,7 +538,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("8.8.4.4", 12345) + local ok, err = sock:connect("106.187.41.147", 12345) if not ok then ngx.say("failed to connect: ", err) return From 2875695b7b8bc2bf07dda27ebc031df88f23d5cd Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 17:33:41 -0800 Subject: [PATCH 0239/2239] bugfix: setting the "eof" argument (i.e., ngx.arg[2]) in body_filter_by_lua for a subrequest could truncate the main request's response data stream. --- src/ngx_http_lua_bodyfilterby.c | 61 ++++++++++++++++++++++++++++----- src/ngx_http_lua_common.h | 2 ++ t/082-body-filter.t | 24 +++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 92ce2fedb1..618c201c83 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -284,6 +284,16 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } } + if (ctx->seen_last_in_filter) { + for (/* void */; in; in = in->next) { + dd("mark the buf as consumed: %d", (int) ngx_buf_size(in->buf)); + in->buf->pos = in->buf->last; + in->buf->file_pos = in->buf->file_last; + } + + return NGX_OK; + } + if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { @@ -420,7 +430,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L) size += b->last - b->pos; - if (b->last_buf) { + if (b->last_buf || b->last_in_chain) { break; } } @@ -431,7 +441,7 @@ ngx_http_lua_body_filter_param_get(lua_State *L) b = cl->buf; p = ngx_copy(p, b->pos, b->last - b->pos); - if (b->last_buf) { + if (b->last_buf || b->last_in_chain) { break; } } @@ -474,7 +484,13 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, if (in) { for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { - cl->buf->last_buf = 1; + if (r == r->main) { + cl->buf->last_buf = 1; + + } else { + cl->buf->last_in_chain = 1; + } + break; } } @@ -490,7 +506,12 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "out of memory"); } - cl->buf->last_buf = 1; + if (r == r->main) { + cl->buf->last_buf = 1; + + } else { + cl->buf->last_in_chain = 1; + } lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); @@ -506,6 +527,10 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, cl->buf->last_buf = 0; } + if (cl->buf->last_in_chain) { + cl->buf->last_in_chain = 0; + } + size += cl->buf->last - cl->buf->pos; } @@ -542,6 +567,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, for (cl = in; cl; cl = cl->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; + cl->buf->file_pos = cl->buf->file_last; } lua_pushlightuserdata(L, NULL); /* key val */ @@ -566,7 +592,7 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, last = 0; for (cl = in; cl; cl = cl->next) { - if (cl->buf->last_buf) { + if (cl->buf->last_buf || cl->buf->last_in_chain) { last = 1; } @@ -577,7 +603,12 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, if (size == 0) { if (last) { if (in) { - in->buf->last_buf = 1; + if (r == r->main) { + in->buf->last_buf = 1; + + } else { + in->buf->last_in_chain = 1; + } } else { @@ -591,7 +622,12 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return luaL_error(L, "out of memory"); } - cl->buf->last_buf = 1; + if (r == r->main) { + cl->buf->last_buf = 1; + + } else { + in->buf->last_in_chain = 1; + } lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); @@ -617,7 +653,16 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, cl->buf->last = ngx_copy(cl->buf->pos, data, size); } - cl->buf->last_buf = last; + if (last) { + if (r == r->main) { + cl->buf->last_buf = 1; + + } else { + cl->buf->last_in_chain = 1; + } + + ctx->seen_last_in_filter = 1; + } lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 2dde936001..51068fbd6f 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -357,6 +357,8 @@ typedef struct ngx_http_lua_ctx_s { unsigned no_abort:1; /* prohibit "world abortion" via ngx.exit() and etc */ + + unsigned seen_last_in_filter:1; /* used by body_filter_by_lua* */ } ngx_http_lua_ctx_t; diff --git a/t/082-body-filter.t b/t/082-body-filter.t index 8659feaf61..7fe3eae900 100644 --- a/t/082-body-filter.t +++ b/t/082-body-filter.t @@ -483,3 +483,27 @@ in function 'error' in function 'bar' in function 'foo' + + +=== TEST 18: setting "eof" in subrequests +--- config + location /t { + echo_location /read; + echo_location /read; + } + + location /read { + echo -n hello world; + echo -n hiya globe; + + body_filter_by_lua ' + ngx.arg[2] = 1 + '; + } +--- request +GET /t +--- response_body chop +hello worldhello world +--- no_error_log +[error] + From c8c56883971c4b12afc5e0e519aa4756128a5e94 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 17:39:51 -0800 Subject: [PATCH 0240/2239] docs: documented the ngx.quote_sql_str API. also updated the docs for body_filter_by_lua* regarding the "eof" argument in subrequests. --- README | 17 +++++++++++++---- README.markdown | 10 +++++++++- doc/HttpLuaModule.wiki | 9 ++++++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/README b/README index 29778ffb3d..560e8be127 100644 --- a/README +++ b/README @@ -871,10 +871,10 @@ Directives and the "eof" flag indicating the end of the response body data stream is passed via ngx.arg[2] (as a Lua boolean value). - Behind the scene, the "eof" flag is just the "last_buf" flag of the - nginx chain link buffers. And in the context of an Nginx subrequest, - there is no "eof" flag at all, due to the underlying limitation in the - Nginx core. + 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.) The output data stream can be aborted immediately by running the following Lua statement: @@ -3379,6 +3379,15 @@ Nginx API for Lua 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** + + Returns a quoted SQL string literal according to the MySQL quoting + rules. + ngx.today syntax: *str = ngx.today()* diff --git a/README.markdown b/README.markdown index c78f885a7c..925f0b9253 100644 --- a/README.markdown +++ b/README.markdown @@ -771,7 +771,7 @@ 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). -Behind the scene, the "eof" flag is just the `last_buf` flag of the nginx chain link buffers. And in the context of an Nginx subrequest, there is no "eof" flag at all, due to the underlying limitation in the Nginx core. +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.) The output data stream can be aborted immediately by running the following Lua statement: @@ -3113,6 +3113,14 @@ This function requires SHA-1 support in the Nginx build. (This usually just mean 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** + +Returns a quoted SQL string literal according to the MySQL quoting rules. + ngx.today --------- **syntax:** *str = ngx.today()* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f02c78385a..3c0578b443 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -743,7 +743,7 @@ Uses Lua code specified in to define an output bod The input data chunk is passed via [[#ngx.arg|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|ngx.arg]][2] (as a Lua boolean value). -Behind the scene, the "eof" flag is just the last_buf flag of the nginx chain link buffers. And in the context of an Nginx subrequest, there is no "eof" flag at all, due to the underlying limitation in the Nginx core. +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.) The output data stream can be aborted immediately by running the following Lua statement: @@ -3011,6 +3011,13 @@ This function requires SHA-1 support in the Nginx build. (This usually just mean 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*'' + +Returns a quoted SQL string literal according to the MySQL quoting rules. + == ngx.today == '''syntax:''' ''str = ngx.today()'' From e46baf0adc56afa92d361f15f12df49b52613a8e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 18:17:01 -0800 Subject: [PATCH 0241/2239] bugfix: commit 2875695b was incomplete. --- src/ngx_http_lua_bodyfilterby.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 618c201c83..5bd98fbe3a 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -481,6 +481,8 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, in = lua_touserdata(L, -1); if (last) { + ctx->seen_last_in_filter = 1; + if (in) { for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { @@ -654,14 +656,14 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, } if (last) { + ctx->seen_last_in_filter = 1; + if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } - - ctx->seen_last_in_filter = 1; } lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); From a6d8faf2bbfcda87e06b17da67e9f66777dd2c0e Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 18:25:36 -0800 Subject: [PATCH 0242/2239] feature: implemented named subpatterns for ngx.re.match, ngx.re.gmatch, ngx.re.sub, and ngx.re.gsub; also added new regex option "D" to allow duplicate named subpatterns. thanks Ray Bejjani for the patch in github pull #182. --- README | 25 +++++- README.markdown | 26 +++++- doc/HttpLuaModule.wiki | 26 +++++- src/ngx_http_lua_regex.c | 147 +++++++++++++++++++++++++++++++++ t/034-match.t | 133 +++++++++++++++++++++++++++++- t/035-gmatch.t | 170 +++++++++++++++++++++++++++++++++++++++ t/036-sub.t | 60 ++++++++++++++ t/037-gsub.t | 21 +++++ t/038-match-o.t | 102 +++++++++++++++++++++++ t/039-sub-o.t | 39 +++++++++ t/040-gsub-o.t | 21 +++++ 11 files changed, 763 insertions(+), 7 deletions(-) diff --git a/README b/README index 560e8be127..49919b2ed1 100644 --- a/README +++ b/README @@ -3537,13 +3537,25 @@ Nginx API for Lua -- m[0] == "1234" -- m[1] == "1" - Unmatched sub-patterns will have "nil" values in their "captures" table + 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]+)") + -- m[0] == "1234" + -- m[1] == "1" + -- m[2] == "234" + -- m["remaining"] == "234" + + Unmatched subpatterns will have "nil" values in their "captures" table fields. - local m = ngx.re.match("hello, world", "(world)|(hello)") + local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" + -- m[3] == nil + -- m["named"] == nil Specify "options" to control how the match operation will be performed. The following option characters are supported: @@ -3573,6 +3585,15 @@ Nginx API for Lua x extended mode (similar to Perl's /x modifier) + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. + These options can be combined: local m = ngx.re.match("hello, world", "HEL LO", "ix") diff --git a/README.markdown b/README.markdown index 925f0b9253..9a1324baf0 100644 --- a/README.markdown +++ b/README.markdown @@ -3255,13 +3255,26 @@ When a match is found, a Lua table `captures` is returned, where `captures[0]` h -- m[1] == "1" -Unmatched sub-patterns will have `nil` values in their `captures` table fields. +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, world", "(world)|(hello)") + local m = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + -- m[0] == "1234" + -- m[1] == "1" + -- m[2] == "234" + -- m["remaining"] == "234" + + +Unmatched subpatterns will have `nil` values in their `captures` table fields. + + + local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" + -- m[3] == nil + -- m["named"] == nil Specify `options` to control how the match operation will be performed. The following option characters are supported: @@ -3292,6 +3305,15 @@ Specify `options` to control how the match operation will be performed. The foll x extended mode (similar to Perl's /x modifier) + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. + These options can be combined: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 3c0578b443..af7b9a8edf 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3141,13 +3141,26 @@ When a match is found, a Lua table captures is returned, where -Unmatched sub-patterns will have nil values in their captures table fields. +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, world", "(world)|(hello)") + local m = ngx.re.match("hello, 1234", "([0-9])(?[0-9]+)") + -- m[0] == "1234" + -- m[1] == "1" + -- m[2] == "234" + -- m["remaining"] == "234" + + +Unmatched subpatterns will have nil values in their captures table fields. + + + local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") -- m[0] == "hello" -- m[1] == nil -- m[2] == "hello" + -- m[3] == nil + -- m["named"] == nil Specify options to control how the match operation will be performed. The following option characters are supported: @@ -3177,6 +3190,15 @@ Specify options to control how the match operation will be performe the --enable-utf8 option or else a Lua exception will be thrown. x extended mode (similar to Perl's /x modifier) + + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. These options can be combined: diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 9135b963bf..e56197a7e1 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -30,6 +30,7 @@ #define NGX_LUA_RE_COMPILE_ONCE (1<<0) #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_DFA_MODE_WORKSPACE_COUNT (100) @@ -80,6 +81,9 @@ static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, static ngx_int_t ngx_lua_regex_compile(ngx_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, + u_char *name_table, int name_count, int name_entry_size, + unsigned flags, ngx_str_t *subj); #define ngx_http_lua_regex_exec(re, e, s, start, captures, size) \ @@ -116,6 +120,8 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_http_lua_main_conf_t *lmcf = NULL; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; + int name_entry_size, name_count; + u_char *name_table; nargs = lua_gettop(L); @@ -390,6 +396,29 @@ ngx_http_lua_ngx_re_match(lua_State *L) } exec: + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT, + &name_count) != 0) + { + msg = "cannot acquire named subpattern count"; + goto error; + } + + if (name_count > 0) { + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE, + &name_entry_size) != 0) + { + msg = "cannot acquire named subpattern entry size"; + goto error; + } + + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE, + &name_table) != 0) + { + msg = "cannot acquire named subpattern table"; + goto error; + } + } + if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA @@ -463,6 +492,11 @@ ngx_http_lua_ngx_re_match(lua_State *L) lua_rawseti(L, -2, (int) i); } + if (name_count > 0) { + ngx_http_lua_re_collect_named_captures(L, name_table, name_count, + name_entry_size, flags, &subj); + } + if (nargs == 4) { /* having ctx table */ pos = cap[1]; lua_pushinteger(L, (lua_Integer) pos); @@ -838,6 +872,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; /* upvalues in order: subj ctx offset */ @@ -870,6 +906,29 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) dd("regex exec..."); + if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMECOUNT, + &name_count) != 0) + { + msg = "cannot acquire named subpattern count"; + goto error; + } + + if (name_count > 0) { + if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMEENTRYSIZE, + &name_entry_size) != 0) + { + msg = "cannot acquire named subpattern entry size"; + goto error; + } + + if (pcre_fullinfo(ctx->regex, NULL, PCRE_INFO_NAMETABLE, + &name_table) != 0) + { + msg = "cannot acquire named subpattern table"; + goto error; + } + } + if (ctx->flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA @@ -943,6 +1002,12 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) lua_rawseti(L, -2, (int) i); } + if (name_count > 0) { + ngx_http_lua_re_collect_named_captures(L, name_table, name_count, + name_entry_size, ctx->flags, + &subj); + } + offset = cap[1]; if (offset == cap[0]) { offset++; @@ -1032,6 +1097,11 @@ ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_lua_regex_compile_t *re, re->options |= PCRE_ANCHORED; break; + case 'D': + re->options |= PCRE_DUPNAMES; + flags |= NGX_LUA_RE_MODE_DUPNAMES; + break; + default: msg = lua_pushfstring(L, "unknown flag \"%c\"", *p); return luaL_argerror(L, narg, msg); @@ -1094,6 +1164,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; ngx_http_lua_complex_value_t *ctpl = NULL; ngx_http_lua_compile_complex_value_t ccv; @@ -1442,6 +1514,29 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) offset = 0; cp_offset = 0; + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT, + &name_count) != 0) + { + msg = "cannot acquire named subpattern count"; + goto error; + } + + if (name_count > 0) { + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE, + &name_entry_size) != 0) + { + msg = "cannot acquire named subpattern entry size"; + goto error; + } + + if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE, + &name_table) != 0) + { + msg = "cannot acquire named subpattern table"; + goto error; + } + } + for (;;) { if (flags & NGX_LUA_RE_MODE_DFA) { @@ -1512,6 +1607,13 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) lua_rawseti(L, -2, (int) i); } + if (name_count > 0) { + ngx_http_lua_re_collect_named_captures(L, name_table, + name_count, + name_entry_size, + flags, &subj); + } + dd("stack size at call: %d", lua_gettop(L)); lua_call(L, 1 /* nargs */, 1 /* nresults */); @@ -1773,5 +1875,50 @@ ngx_http_lua_ngx_re_gmatch_gc(lua_State *L) } +static void +ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, + int name_count, int name_entry_size, unsigned flags, ngx_str_t *subj) +{ + int i, n; + size_t len; + u_char *name_entry; + char *name; + + for (i = 0; i < name_count; i++) { + + name_entry = &name_table[i * name_entry_size]; + n = (name_entry[0] << 8) | name_entry[1]; + name = (char *) &name_entry[2]; + + if (flags & NGX_LUA_RE_MODE_DUPNAMES) { + lua_getfield(L, -1, name); + + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + + /* 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_rawgeti(L, -2, n); + lua_rawseti(L, -2, (int) len + 1); + + /* pop the m[name] array we pulled in */ + lua_pop(L, 1); + + } else { + lua_pushstring(L, name); + lua_rawgeti(L, -2, n); + lua_rawset(L, -3); + } + } +} + + #endif /* NGX_PCRE */ diff --git a/t/034-match.t b/t/034-match.t index 5f17f0513c..276fa094e9 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 + 5); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); no_long_string(); @@ -726,3 +726,134 @@ m: --- no_error_log [error] + + +=== TEST 35: named subpatterns w/ extraction +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, 1234", "(?[a-z]+), [0-9]+") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m.first) + ngx.say(m.second) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, 1234 +hello +hello +nil + + + +=== TEST 36: duplicate named subpatterns w/ extraction +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(table.concat(m.first,"-")) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, 1234 +hello +1234 +hello-1234 + + + +=== TEST 37: named captures are empty strings +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("1234", "(?[a-z]*)([0-9]+)") + if m then + ngx.say(m[0]) + ngx.say(m.first) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 + + +1234 + + + +=== TEST 38: named captures are nil +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m[3]) + ngx.say(m["named"]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello +nil +hello +nil +nil + + + +=== TEST 39: duplicate named subpatterns +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, world", + "(?\\\\w+), (?\\\\w+)", + "D") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(table.concat(m.named,"-")) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, world +hello +world +hello-world +--- no_error_log +[error] + diff --git a/t/035-gmatch.t b/t/035-gmatch.t index 02d1723959..2d66de425d 100644 --- a/t/035-gmatch.t +++ b/t/035-gmatch.t @@ -511,3 +511,173 @@ matched: [] matched: [] matched: [] + + +=== TEST 21: gmatch with named pattern +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("1234, 1234", "(?[0-9]+)") + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m["first"]) + else + ngx.say("not matched!") + end + + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m["first"]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 +1234 +1234 +1234 +1234 +1234 + + + +=== TEST 22: gmatch with multiple named pattern +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("1234, abcd, 1234", "(?[0-9]+)|(?[a-z]+)") + + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m["first"]) + ngx.say(m["second"]) + else + ngx.say("not matched!") + end + + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m["first"]) + ngx.say(m["second"]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 +1234 +nil +1234 +nil +abcd +nil +abcd +nil +abcd + + + +=== TEST 23: gmatch with duplicate named pattern w/ extraction +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("hello, 1234", "(?[a-z]+), (?[0-9]+)", "D") + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(table.concat(m.first,"-")) + else + ngx.say("not matched!") + end + + m = it() + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(table.concat(m.first,"-")) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, 1234 +hello +1234 +hello-1234 +not matched! + + + +=== TEST 24: named captures are empty +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("1234", "(?[a-z]*)([0-9]+)", "") + local m = it() + if m then + ngx.say(m[0]) + ngx.say(m.first) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 + + +1234 + + + +=== TEST 25: named captures are empty (with regex cache) +--- config + location /re { + content_by_lua ' + local it = ngx.re.gmatch("1234", "(?[a-z]*)([0-9]+)", "o") + local m = it() + if m then + ngx.say(m[0]) + ngx.say(m.first) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 + + +1234 + diff --git a/t/036-sub.t b/t/036-sub.t index 53d39c1648..b266a75b68 100644 --- a/t/036-sub.t +++ b/t/036-sub.t @@ -366,3 +366,63 @@ nil --- response_body howdy, world + + +=== TEST 20: matched and with variables w/o using named patterns in sub +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("a b c d", "(?b) (?c)", "[$0] [$1] [$2] [$3] [$134]") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +a [b c] [b] [c] [] [] d +1 + + + +=== TEST 21: matched and with variables using named patterns in func +--- config + error_log /tmp/nginx_error debug; + location /re { + content_by_lua ' + local repl = function (m) + return "[" .. m[0] .. "] [" .. m["first"] .. "] [" .. m[2] .. "]" + end + + local s, n = ngx.re.sub("a b c d", "(?b) (?c)", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +a [b c] [b] [c] d +1 + + + +=== TEST 22: matched and with variables w/ using named patterns in sub +This is still a TODO +--- SKIP +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("a b c d", "(?b) (?c)", "[$0] [${first}] [${second}] [$3] [$134]") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +a [b c] [b] [c] [] [] d +1 +--- no_error_log +[error] + diff --git a/t/037-gsub.t b/t/037-gsub.t index 68d88e255d..8143406816 100644 --- a/t/037-gsub.t +++ b/t/037-gsub.t @@ -363,3 +363,24 @@ n: 1 --- no_error_log [error] + + +=== TEST 18: named pattern repl w/ callback +--- config + location /re { + content_by_lua ' + local repl = function (m) + return "[" .. m[0] .. "," .. m["first"] .. "]" + end + + local s, n = ngx.re.gsub("hello, world", "(?[a-z])[a-z]+", repl) + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +[hello,h], [world,w] +2 + diff --git a/t/038-match-o.t b/t/038-match-o.t index 5d9e13370c..c96683ad0e 100644 --- a/t/038-match-o.t +++ b/t/038-match-o.t @@ -636,3 +636,105 @@ nil 567 98 + + +=== TEST 30: named subpatterns w/ extraction +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, 1234", "(?[a-z]+), [0-9]+", "o") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m.first) + ngx.say(m.second) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, 1234 +hello +hello +nil + + + +=== TEST 31: duplicate named subpatterns w/ extraction +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, 1234", "(?[a-z]+), (?[0-9]+)", "Do") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(table.concat(m.first,"-")) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello, 1234 +hello +1234 +hello-1234 + + + +=== TEST 32: named captures are empty strings +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("1234", "(?[a-z]*)([0-9]+)", "o") + if m then + ngx.say(m[0]) + ngx.say(m.first) + ngx.say(m[1]) + ngx.say(m[2]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +1234 + + +1234 + + + +=== TEST 33: named captures are nil +--- config + location /re { + content_by_lua ' + local m = ngx.re.match("hello, world", "(world)|(hello)|(?howdy)", "o") + if m then + ngx.say(m[0]) + ngx.say(m[1]) + ngx.say(m[2]) + ngx.say(m[3]) + ngx.say(m["named"]) + else + ngx.say("not matched!") + end + '; + } +--- request + GET /re +--- response_body +hello +nil +hello +nil +nil + diff --git a/t/039-sub-o.t b/t/039-sub-o.t index 124e910ac1..2eb894e11a 100644 --- a/t/039-sub-o.t +++ b/t/039-sub-o.t @@ -522,3 +522,42 @@ hello, hi, 1 + + +=== TEST 25: matched and with variables w/o using named patterns in sub +--- config + location /re { + content_by_lua ' + local s, n = ngx.re.sub("a b c d", "(?b) (?c)", "[$0] [$1] [$2] [$3] [$134]", "o") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +a [b c] [b] [c] [] [] d +1 + + + +=== TEST 26: matched and with variables using named patterns in func +--- config + error_log /tmp/nginx_error debug; + location /re { + content_by_lua ' + local repl = function (m) + return "[" .. m[0] .. "] [" .. m["first"] .. "] [" .. m[2] .. "]" + end + + local s, n = ngx.re.sub("a b c d", "(?b) (?c)", repl, "o") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +a [b c] [b] [c] d +1 + diff --git a/t/040-gsub-o.t b/t/040-gsub-o.t index 2e631ccb51..159a26430d 100644 --- a/t/040-gsub-o.t +++ b/t/040-gsub-o.t @@ -179,3 +179,24 @@ hello, world {foohbarhbaz} 2 + + +=== TEST 10: named pattern repl w/ callback +--- config + location /re { + content_by_lua ' + local repl = function (m) + return "[" .. m[0] .. "," .. m["first"] .. "]" + end + + local s, n = ngx.re.gsub("hello, world", "(?[a-z])[a-z]+", repl, "o") + ngx.say(s) + ngx.say(n) + '; + } +--- request + GET /re +--- response_body +[hello,h], [world,w] +2 + From b8af0b925e6dc6e41ab23514e0f00f67ddf02122 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Wed, 23 Jan 2013 20:21:47 -0800 Subject: [PATCH 0243/2239] fixed the missing bits for commit 0d120033. --- t/024-access/uthread-exit.t | 2 +- t/094-uthread-exit.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/024-access/uthread-exit.t b/t/024-access/uthread-exit.t index bf604808c2..302d2b7c47 100644 --- a/t/024-access/uthread-exit.t +++ b/t/024-access/uthread-exit.t @@ -519,7 +519,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("8.8.4.4", 12345) + local ok, err = sock:connect("106.187.41.147", 12345) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/094-uthread-exit.t b/t/094-uthread-exit.t index d576a07936..593cfe0ab5 100644 --- a/t/094-uthread-exit.t +++ b/t/094-uthread-exit.t @@ -501,7 +501,7 @@ after ngx.say("after") local sock = ngx.socket.tcp() sock:settimeout(12000) - local ok, err = sock:connect("8.8.4.4", 12345) + local ok, err = sock:connect("106.187.41.147", 12345) if not ok then ngx.say("failed to connect: ", err) return From 07d48739683039b708efbed5b52924a801d9616b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 24 Jan 2013 11:48:51 -0800 Subject: [PATCH 0244/2239] feature: implemented the "J" regex option for the PCRE Javascript compatible mode in the ngx.re API. thanks lhmwzy for requesting this. --- README | 3 +++ README.markdown | 3 +++ doc/HttpLuaModule.wiki | 3 +++ src/ngx_http_lua_regex.c | 4 ++++ t/034-match.t | 23 ++++++++++++++++++++++- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README b/README index 49919b2ed1..0f42a68655 100644 --- a/README +++ b/README @@ -3573,6 +3573,9 @@ Nginx API for Lua this option should always be used together with the 'o' option. first introduced in ngx_lua v0.3.1rc30. + J enable the PCRE Javascript compatible mode. this option was + first introduced in the v0.7.14 release. + m multi-line mode (similar to Perl's /m modifier) o compile-once mode (similar to Perl's /o modifier), diff --git a/README.markdown b/README.markdown index 9a1324baf0..a4de27aa6a 100644 --- a/README.markdown +++ b/README.markdown @@ -3293,6 +3293,9 @@ Specify `options` to control how the match operation will be performed. The foll this option should always be used together with the 'o' option. first introduced in ngx_lua v0.3.1rc30. + J enable the PCRE Javascript compatible mode. this option was + first introduced in the v0.7.14 release. + m multi-line mode (similar to Perl's /m modifier) o compile-once mode (similar to Perl's /o modifier), diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index af7b9a8edf..a1f37ec118 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3179,6 +3179,9 @@ Specify options to control how the match operation will be performe this option should always be used together with the 'o' option. first introduced in ngx_lua v0.3.1rc30. + J enable the PCRE Javascript compatible mode. this option was + first introduced in the v0.7.14 release. + m multi-line mode (similar to Perl's /m modifier) o compile-once mode (similar to Perl's /o modifier), diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index e56197a7e1..cefa8789f8 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1102,6 +1102,10 @@ ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_lua_regex_compile_t *re, flags |= NGX_LUA_RE_MODE_DUPNAMES; break; + case 'J': + re->options |= PCRE_JAVASCRIPT_COMPAT; + break; + default: msg = lua_pushfstring(L, "unknown flag \"%c\"", *p); return luaL_argerror(L, narg, msg); diff --git a/t/034-match.t b/t/034-match.t index 276fa094e9..9273abe6e1 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 + 6); +plan tests => repeat_each() * (blocks() * 2 + 7); #no_diff(); no_long_string(); @@ -857,3 +857,24 @@ hello-world --- no_error_log [error] + + +=== TEST 40: Javascript compatible mode +--- config + location /t { + content_by_lua ' + local m = ngx.re.match("章", [[\\u7AE0]], "uJ") + if m then + ngx.say("matched: ", m[0]) + else + ngx.say("not matched!") + end + '; + } +--- request +GET /t +--- response_body +matched: 章 +--- no_error_log +[error] + From 22cf24c3f272f85297254d86341122925a2ef93f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 24 Jan 2013 11:49:53 -0800 Subject: [PATCH 0245/2239] minor documentation tweaks. --- README | 18 +++++++++--------- README.markdown | 18 +++++++++--------- doc/HttpLuaModule.wiki | 18 +++++++++--------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/README b/README index 0f42a68655..63b99343a5 100644 --- a/README +++ b/README @@ -3566,6 +3566,15 @@ Nginx API for Lua this requires PCRE 6.0+ or else a Lua exception will be thrown. first introduced in ngx_lua v0.3.1rc30. + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. + i case insensitive mode (similar to Perl's /i modifier) j enable PCRE JIT compilation, this requires PCRE 8.21+ which @@ -3588,15 +3597,6 @@ Nginx API for Lua x extended mode (similar to Perl's /x modifier) - D enable duplicate named pattern support. This allows named - subpattern names to be repeated, returning the captures in - an array-like Lua table. for example, - local m = ngx.re.match("hello, world", - "(?\w+), (?\w+)", - "D") - -- m["named"] == {"hello", "world"} - this option was first introduced in the v0.7.14 release. - These options can be combined: local m = ngx.re.match("hello, world", "HEL LO", "ix") diff --git a/README.markdown b/README.markdown index a4de27aa6a..04b5f09e7c 100644 --- a/README.markdown +++ b/README.markdown @@ -3286,6 +3286,15 @@ Specify `options` to control how the match operation will be performed. The foll this requires PCRE 6.0+ or else a Lua exception will be thrown. first introduced in ngx_lua v0.3.1rc30. + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. + i case insensitive mode (similar to Perl's /i modifier) j enable PCRE JIT compilation, this requires PCRE 8.21+ which @@ -3308,15 +3317,6 @@ Specify `options` to control how the match operation will be performed. The foll x extended mode (similar to Perl's /x modifier) - D enable duplicate named pattern support. This allows named - subpattern names to be repeated, returning the captures in - an array-like Lua table. for example, - local m = ngx.re.match("hello, world", - "(?\w+), (?\w+)", - "D") - -- m["named"] == {"hello", "world"} - this option was first introduced in the v0.7.14 release. - These options can be combined: diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index a1f37ec118..401fdcc999 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3172,6 +3172,15 @@ Specify options to control how the match operation will be performe this requires PCRE 6.0+ or else a Lua exception will be thrown. first introduced in ngx_lua v0.3.1rc30. + D enable duplicate named pattern support. This allows named + subpattern names to be repeated, returning the captures in + an array-like Lua table. for example, + local m = ngx.re.match("hello, world", + "(?\w+), (?\w+)", + "D") + -- m["named"] == {"hello", "world"} + this option was first introduced in the v0.7.14 release. + i case insensitive mode (similar to Perl's /i modifier) j enable PCRE JIT compilation, this requires PCRE 8.21+ which @@ -3193,15 +3202,6 @@ Specify options to control how the match operation will be performe the --enable-utf8 option or else a Lua exception will be thrown. x extended mode (similar to Perl's /x modifier) - - D enable duplicate named pattern support. This allows named - subpattern names to be repeated, returning the captures in - an array-like Lua table. for example, - local m = ngx.re.match("hello, world", - "(?\w+), (?\w+)", - "D") - -- m["named"] == {"hello", "world"} - this option was first introduced in the v0.7.14 release. These options can be combined: From a1fe49f434bf6d954e15c7688b808dcdc44e5a9b Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Thu, 24 Jan 2013 18:00:48 -0800 Subject: [PATCH 0246/2239] optimize: we no longer traverse the captured body chain everytime we append a new link to it. --- src/ngx_http_lua_capturefilter.c | 4 +++- src/ngx_http_lua_common.h | 2 ++ src/ngx_http_lua_subrequest.c | 2 ++ src/ngx_http_lua_util.c | 15 +++++---------- src/ngx_http_lua_util.h | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index cb866b465b..ec4bf66590 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -77,6 +77,8 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r) ctx->capture = old_ctx->capture; ctx->index = old_ctx->index; + ctx->body = NULL; + ctx->last_body = &ctx->body; psr_data->ctx = ctx; } } @@ -142,7 +144,7 @@ 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->body, in); + rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->last_body, in); if (rc != NGX_OK) { return NGX_ERROR; } diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 51068fbd6f..fa53cc1f8a 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -303,6 +303,8 @@ typedef struct ngx_http_lua_ctx_s { ngx_chain_t *body; /* buffered subrequest response body chains */ + ngx_chain_t **last_body; /* for the "body" field */ + ngx_str_t exec_uri; ngx_str_t exec_args; diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 9b8e8a025a..54939185b2 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -499,12 +499,14 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL + * 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; diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index ba9072a329..193a84e360 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -795,18 +795,12 @@ 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 **chain, ngx_chain_t *in) + ngx_chain_t ***plast, ngx_chain_t *in) { - ngx_chain_t *cl, **ll; + ngx_chain_t *cl; size_t len; ngx_buf_t *b; - ll = chain; - - for (cl = *chain; cl; cl = cl->next) { - ll = &cl->next; - } - len = 0; for (cl = in; cl; cl = cl->next) { @@ -835,13 +829,14 @@ ngx_http_lua_add_copy_chain(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, while (in) { if (ngx_buf_in_memory(in->buf)) { b->last = ngx_copy(b->last, in->buf->pos, - in->buf->last - in->buf->pos); + in->buf->last - in->buf->pos); } in = in->next; } - *ll = cl; + **plast = cl; + *plast = &cl->next; return NGX_OK; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index b32b8be976..7e3b7f1421 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -82,7 +82,7 @@ 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 **chain, ngx_chain_t *in); + ngx_http_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in); void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L, ngx_http_lua_ctx_t *ctx); From 74221397778957b92032aeb64358cd29c2e027a6 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 25 Jan 2013 11:48:32 -0800 Subject: [PATCH 0247/2239] bugfix: recent versions of ngx_lua failed to compile with old PCRE versions like 6.6 due to the "D" and "J" regex options; now these two regex options require at least PCRE 8.12. thanks Wenhua Zhang for reporting this issue. --- README | 4 +++- README.markdown | 4 +++- doc/HttpLuaModule.wiki | 4 +++- src/ngx_http_lua_regex.c | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README b/README index 63b99343a5..5567973d3e 100644 --- a/README +++ b/README @@ -3574,6 +3574,7 @@ Nginx API for Lua "D") -- m["named"] == {"hello", "world"} this option was first introduced in the v0.7.14 release. + this option requires at least PCRE 8.12. i case insensitive mode (similar to Perl's /i modifier) @@ -3583,7 +3584,8 @@ Nginx API for Lua first introduced in ngx_lua v0.3.1rc30. J enable the PCRE Javascript compatible mode. this option was - first introduced in the v0.7.14 release. + first introduced in the v0.7.14 release. this option requires + at least PCRE 8.12. m multi-line mode (similar to Perl's /m modifier) diff --git a/README.markdown b/README.markdown index 04b5f09e7c..d4e6d50f28 100644 --- a/README.markdown +++ b/README.markdown @@ -3294,6 +3294,7 @@ Specify `options` to control how the match operation will be performed. The foll "D") -- m["named"] == {"hello", "world"} this option was first introduced in the v0.7.14 release. + this option requires at least PCRE 8.12. i case insensitive mode (similar to Perl's /i modifier) @@ -3303,7 +3304,8 @@ Specify `options` to control how the match operation will be performed. The foll first introduced in ngx_lua v0.3.1rc30. J enable the PCRE Javascript compatible mode. this option was - first introduced in the v0.7.14 release. + first introduced in the v0.7.14 release. this option requires + at least PCRE 8.12. m multi-line mode (similar to Perl's /m modifier) diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 401fdcc999..919e66e258 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -3180,6 +3180,7 @@ Specify options to control how the match operation will be performe "D") -- m["named"] == {"hello", "world"} this option was first introduced in the v0.7.14 release. + this option requires at least PCRE 8.12. i case insensitive mode (similar to Perl's /i modifier) @@ -3189,7 +3190,8 @@ Specify options to control how the match operation will be performe first introduced in ngx_lua v0.3.1rc30. J enable the PCRE Javascript compatible mode. this option was - first introduced in the v0.7.14 release. + first introduced in the v0.7.14 release. this option requires + at least PCRE 8.12. m multi-line mode (similar to Perl's /m modifier) diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index cefa8789f8..310c958076 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1097,6 +1097,7 @@ ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_lua_regex_compile_t *re, re->options |= PCRE_ANCHORED; break; +#if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 12) case 'D': re->options |= PCRE_DUPNAMES; flags |= NGX_LUA_RE_MODE_DUPNAMES; @@ -1105,6 +1106,7 @@ ngx_http_lua_ngx_re_parse_opts(lua_State *L, ngx_lua_regex_compile_t *re, case 'J': re->options |= PCRE_JAVASCRIPT_COMPAT; break; +#endif default: msg = lua_pushfstring(L, "unknown flag \"%c\"", *p); From 480ff88583d3b82558e42f68cb6b096b8c123e8d Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Fri, 25 Jan 2013 15:25:56 -0800 Subject: [PATCH 0248/2239] removed most of the leak false positives from valgrind.suppress because we now pass the option --show-possibly-lost=no to valgrind by default. --- valgrind.suppress | 339 ---------------------------------------------- 1 file changed, 339 deletions(-) diff --git a/valgrind.suppress b/valgrind.suppress index 9420ed2efc..d5f8d5c7ae 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,11 +1,5 @@ { -Memcheck:Leak -fun:malloc -fun:ngx_alloc -} -{ - Memcheck:Addr1 fun:ngx_init_cycle fun:ngx_master_process_cycle @@ -73,13 +67,6 @@ fun:ngx_http_lua_ngx_echo fun:lj_str_new fun:lua_pushlstring } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - obj:* -} { exp-sgcheck:SorG @@ -120,22 +107,6 @@ fun:ngx_http_lua_ngx_echo fun:ngx_vslprintf fun:ngx_log_error_core } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_calloc - fun:ngx_event_process_init -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_pcalloc -} { Memcheck:Addr4 @@ -148,26 +119,12 @@ fun:ngx_http_lua_ngx_echo fun:lj_str_new fun:lua_getfield } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:(below main) -} { Memcheck:Param epoll_ctl(event) fun:epoll_ctl } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_event_process_init -} { Memcheck:Cond @@ -182,14 +139,6 @@ fun:ngx_http_lua_ngx_echo fun:ngx_log_error_core fun:ngx_http_charset_header_filter } -{ - - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_pcalloc -} { Memcheck:Addr4 @@ -243,27 +192,6 @@ fun:ngx_http_lua_ngx_echo fun:setsockopt fun:drizzle_state_connect } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_pool_cleanup_add -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_pnalloc -} { Memcheck:Cond @@ -271,70 +199,6 @@ fun:ngx_http_lua_ngx_echo fun:ngx_single_process_cycle fun:main } - -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_pcalloc -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc_large -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_create_pool -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_pnalloc -} - -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_array_push - fun:ngx_http_get_variable_index - fun:ngx_http_memc_add_variable - fun:ngx_http_memc_init - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} - { Memcheck:Leak @@ -342,207 +206,4 @@ fun:ngx_http_lua_ngx_echo fun:ngx_alloc fun:ngx_event_process_init fun:ngx_single_process_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_crc32_table_init - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_event_process_init - fun:ngx_worker_process_init - fun:ngx_worker_process_cycle - fun:ngx_spawn_process - fun:ngx_start_worker_processes - fun:ngx_master_process_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_hash_init - fun:ngx_http_variables_init_vars - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_http_upstream_drizzle_create_srv_conf - fun:ngx_http_upstream - fun:ngx_conf_parse - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_hash_keys_array_init - fun:ngx_http_variables_add_core_vars - fun:ngx_http_core_preconfiguration - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_array_push - fun:ngx_hash_add_key - fun:ngx_http_add_variable - fun:ngx_http_echo_add_variables - fun:ngx_http_echo_handler_init - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_http_upstream_drizzle_create_srv_conf - fun:ngx_http_core_server - fun:ngx_conf_parse - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_http_upstream_drizzle_create_srv_conf - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_array_push - fun:ngx_hash_add_key - fun:ngx_http_variables_add_core_vars - fun:ngx_http_core_preconfiguration - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_hash_init - fun:ngx_http_upstream_init_main_conf - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_pcalloc - fun:ngx_http_drizzle_keepalive_init - fun:ngx_http_upstream_drizzle_init - fun:ngx_http_upstream_init_main_conf - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_palloc_large - fun:ngx_palloc - fun:ngx_hash_init - fun:ngx_http_variables_init_vars - fun:ngx_http_block - fun:ngx_conf_parse - fun:ngx_init_cycle - fun:main -} -{ - - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_create_pool -} -{ - - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_palloc_block - fun:ngx_palloc } From e37b58e372467ea5ca3161c5785f1c2c0d30d27f Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 26 Jan 2013 15:04:03 -0800 Subject: [PATCH 0249/2239] bugfix: for nginx 1.3.9+ compatibility, we now throw an error in ngx.req.init_body(), ngx.req.set_body_data(), and ngx.req.set_body_file() when calling them without calling ngx.req.read_body() or after calling ngx.req.discard_body(). --- src/ngx_http_lua_req_body.c | 94 +++++++++++---------------- t/044-req-body.t | 126 +++++++++++++++++++++--------------- 2 files changed, 113 insertions(+), 107 deletions(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 56f449c3ae..d4cdfff44a 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -374,26 +374,16 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) return luaL_error(L, "request object not found"); } - if (r->request_body == NULL) { - -#if 1 - rc = ngx_http_discard_request_body(r); - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to discard request body"); - } -#endif - - 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 (r->discard_body) { + return luaL_error(L, "request body already discarded asynchronously"); + } - } else { - rb = r->request_body; + if (r->request_body == NULL) { + return luaL_error(L, "request body not read yet"); } + rb = r->request_body; + tag = (ngx_buf_tag_t) &ngx_http_lua_module; tf = rb->temp_file; @@ -527,7 +517,6 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; - ngx_int_t rc; size_t size; lua_Integer num; #if 1 @@ -546,6 +535,14 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); + if (r->discard_body) { + return luaL_error(L, "request body already discarded asynchronously"); + } + + if (r->request_body == NULL) { + return luaL_error(L, "request body not read yet"); + } + if (n == 1) { num = luaL_checkinteger(L, 1); if (num <= 0) { @@ -567,25 +564,7 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) } } - if (r->request_body == NULL) { - -#if 1 - rc = ngx_http_discard_request_body(r); - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to discard request body"); - } -#endif - - 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; - - } else { - rb = r->request_body; - } + rb = r->request_body; #if 1 tf = rb->temp_file; @@ -844,6 +823,14 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) return luaL_error(L, "request object not found"); } + if (r->discard_body) { + return luaL_error(L, "request body already discarded asynchronously"); + } + + if (r->request_body == NULL) { + return luaL_error(L, "request body not read yet"); + } + name.data = ngx_palloc(r->pool, name.len + 1); if (name.data == NULL) { return luaL_error(L, "out of memory"); @@ -862,25 +849,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) dd("clean: %d", (int) clean); - if (r->request_body == NULL) { - -#if 1 - rc = ngx_http_discard_request_body(r); - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return luaL_error(L, "failed to discard request body"); - } -#endif - - 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; - - } else { - rb = r->request_body; - } + rb = r->request_body; /* clean up existing r->request_body->bufs (if any) */ @@ -1098,6 +1067,19 @@ ngx_http_lua_write_request_body(ngx_http_request_t *r, ngx_chain_t *body) } rb->temp_file = tf; + + if (body == NULL) { + /* empty body with r->request_body_in_file_only */ + + if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, + tf->persistent, tf->clean, tf->access) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; + } } n = ngx_write_chain_to_temp_file(rb->temp_file, body); diff --git a/t/044-req-body.t b/t/044-req-body.t index 7f3a96eb7b..43ed0a5eb6 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 5); +plan tests => repeat_each() * (blocks() * 3 + 37); #no_diff(); no_long_string(); @@ -299,25 +299,23 @@ hello, baby location = /sleep { echo_sleep 0.5; } ---- pipelined_requests eval -["POST /test\nyeah", "POST /test\nblah"] ---- response_body eval -["hello, baby -hello, baby -", -"hello, baby -hello, baby -"] +--- request +POST /test +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 --- no_error_log -[error] +[alert] === TEST 14: read buffered body to file and reset it to a new file --- config - client_body_in_file_only on; location = /test { + client_body_in_file_only on; set $old ''; set $new ''; rewrite_by_lua ' @@ -354,9 +352,8 @@ Will you change this world? === TEST 15: read buffered body to file and reset it to a new file --- config - client_body_in_file_only on; - location = /test { + client_body_in_file_only on; set $old ''; set $new ''; rewrite_by_lua ' @@ -499,14 +496,16 @@ Will you change this world? -=== TEST 19: no request body and reset it to a new file (auto-clean) +=== TEST 19: request body discarded and reset it to a new file (auto-clean) --- config client_body_in_file_only off; + client_header_buffer_size 80; location = /test { set $old ''; set $new ''; rewrite_by_lua ' + ngx.req.discard_body() local a_file = ngx.var.realpath_root .. "/a.txt" ngx.req.set_body_file(a_file, false) '; @@ -516,21 +515,18 @@ Will you change this world? echo_read_request_body; echo_request_body; } ---- pipelined_requests eval -["POST /test -hello, world", -"POST /test -hey, you"] +--- request +POST /test +hello, world + --- user_files >>> a.txt Will you change this world? ---- response_body eval -["Will you change this world?\n", -"Will you change this world?\n"] ---- error_code eval -[200, 200] + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 --- no_error_log -[error] +[alert] @@ -551,22 +547,19 @@ Will you change this world? echo_read_request_body; echo_request_body; } ---- pipelined_requests eval -["POST /test -hello, world", -"POST /test -hey, you"] +--- request +POST /test +hello, world + --- user_files >>> a.txt Will you change this world? ---- response_body eval -["Will you change this world?\n", -qr/500 Internal Server Error/] ---- error_code eval -[200, 500] ---- error_log eval -[qr{\[error\].*? lua entry thread aborted: runtime error: \[string "rewrite_by_lua"\]:3: stat\(\) "[^"]+/a\.txt" failed} -] +--- 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 +--- no_error_log +[alert] @@ -611,19 +604,18 @@ hiya, dear dear friend! echo_read_request_body; echo_request_body; } ---- pipelined_requests eval -["POST /test -hello, world", -"POST /test -hey, you"] +--- request +POST /test +hello, world + --- user_files >>> a.txt Will you change this world? ---- response_body eval -["Will you change this world?\n", -qr/500 Internal Server Error/] ---- error_code eval -[200, 500] + +--- response_body_like: 500 Internal Server Error +--- error_code: 500 +--- no_error_log +[alert] @@ -652,6 +644,7 @@ hello, world"] --- config location = /test { rewrite_by_lua ' + ngx.req.read_body() ngx.req.set_body_data("") '; proxy_pass http://127.0.0.1:$server_port/echo; @@ -678,6 +671,7 @@ hello, world"] --- config location = /test { rewrite_by_lua ' + ngx.req.read_body() ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt") '; proxy_pass http://127.0.0.1:$server_port/echo; @@ -843,6 +837,7 @@ srcache_store: request body len: 55 --- config location /t { content_by_lua ' + ngx.req.read_body() ngx.req.init_body(4) ngx.req.append_body("h") ngx.req.append_body("ell") @@ -877,6 +872,7 @@ body: hell --- config location /t { content_by_lua ' + ngx.req.read_body() ngx.req.init_body(4) ngx.req.append_body("h") ngx.req.append_body("ell") @@ -932,11 +928,37 @@ a client request body is buffered to a temporary file +=== TEST 33: init & append & finish (use default buffer size) - body not read yet +--- config + location /t { + client_body_buffer_size 4; + content_by_lua ' + ngx.req.init_body() + ngx.req.append_body("h") + ngx.req.append_body("ell") + ngx.req.finish_body() + + ngx.say("content length: ", ngx.var.http_content_length) + + local data = ngx.req.get_body_data() + ngx.say("body: ", data) + + '; + } +--- request + GET /t +--- 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 + + === TEST 33: init & append & finish (use default buffer size) --- config location /t { client_body_buffer_size 4; content_by_lua ' + ngx.req.read_body() ngx.req.init_body() ngx.req.append_body("h") ngx.req.append_body("ell") @@ -965,6 +987,7 @@ a client request body is buffered to a temporary file --- config location /t { rewrite_by_lua ' + ngx.req.read_body() ngx.req.init_body(4) ngx.req.append_body("h") ngx.req.append_body("ell") @@ -1009,6 +1032,7 @@ a client request body is buffered to a temporary file --- config location /t { rewrite_by_lua ' + ngx.req.read_body() ngx.req.init_body(4) ngx.req.append_body("h") ngx.req.append_body("ell") @@ -1288,13 +1312,13 @@ a client request body is buffered to a temporary file -=== TEST 40: calling ngx.req.socket after ngx.req.init_body +=== TEST 40: calling ngx.req.socket after ngx.req.read_body --- config location = /t { client_body_buffer_size 100; lua_socket_buffer_size 100; content_by_lua ' - ngx.req.init_body() + ngx.req.read_body() local sock, err = ngx.req.socket() if not sock then From 5af60191ef142267f0212b8bab068858e94b6c91 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 26 Jan 2013 20:06:53 -0800 Subject: [PATCH 0250/2239] updated docs to reflect recent changes. --- README | 20 -------------------- README.markdown | 7 ------- doc/HttpLuaModule.wiki | 7 ------- 3 files changed, 34 deletions(-) diff --git a/README b/README index 5567973d3e..61d345b93a 100644 --- a/README +++ b/README @@ -2689,17 +2689,6 @@ Nginx API for Lua body's memory will be freed or the disk file will be cleaned up immediately, respectively. - This function requires patching the Nginx core to function properly - because the Nginx core does not allow modifying request bodies by the - current design. Here is a patch for Nginx 1.0.11: - nginx-1.0.11-allow_request_body_updating.patch - (), and this patch should be - applied cleanly to other releases of Nginx as well. - - This patch has already been applied to ngx_openresty - () 1.0.8.17 and above. - This function was first introduced in the "v0.3.1rc18" release. See also ngx.req.set_body_file. @@ -2727,15 +2716,6 @@ Nginx API for Lua body's memory will be freed or the disk file will be cleaned up immediately, respectively. - This function requires patching the Nginx core to function properly - because the Nginx core does not allow modifying request bodies by the - current design. Here is a patch for Nginx 1.0.9: - nginx-1.0.9-allow_request_body_updating.patch - (), and this patch should be applied - cleanly to other releases of Nginx as well. This patch has already been - applied to ngx_openresty () 1.0.8.17 and above. - This function was first introduced in the "v0.3.1rc18" release. See also ngx.req.set_body_data. diff --git a/README.markdown b/README.markdown index d4e6d50f28..637abdc402 100644 --- a/README.markdown +++ b/README.markdown @@ -2494,10 +2494,6 @@ Set the current request's request body using the in-memory data specified by the If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. -This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.11: [nginx-1.0.11-allow_request_body_updating.patch](https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.11-allow_request_body_updating.patch), and this patch should be applied cleanly to other releases of Nginx as well. - -This patch has already been applied to [ngx_openresty](http://openresty.org/) 1.0.8.17 and above. - This function was first introduced in the `v0.3.1rc18` release. See also [ngx.req.set_body_file](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_body_file). @@ -2516,9 +2512,6 @@ Please ensure that the file specified by the `file_name` argument exists and is If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. -This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.9: [nginx-1.0.9-allow_request_body_updating.patch](https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.9-allow_request_body_updating.patch), and this patch should be applied cleanly to other releases of Nginx as well. -This patch has already been applied to [ngx_openresty](http://openresty.org/) 1.0.8.17 and above. - This function was first introduced in the `v0.3.1rc18` release. See also [ngx.req.set_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_body_data). diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 919e66e258..47dafe895e 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -2420,10 +2420,6 @@ Set the current request's request body using the in-memory data specified by the If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. -This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.11: [https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.11-allow_request_body_updating.patch nginx-1.0.11-allow_request_body_updating.patch], and this patch should be applied cleanly to other releases of Nginx as well. - -This patch has already been applied to [http://openresty.org/ ngx_openresty] 1.0.8.17 and above. - This function was first introduced in the v0.3.1rc18 release. See also [[#ngx.req.set_body_file|ngx.req.set_body_file]]. @@ -2441,9 +2437,6 @@ Please ensure that the file specified by the file_name argument exi If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively. -This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.9: [https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.9-allow_request_body_updating.patch nginx-1.0.9-allow_request_body_updating.patch], and this patch should be applied cleanly to other releases of Nginx as well. -This patch has already been applied to [http://openresty.org/ ngx_openresty] 1.0.8.17 and above. - This function was first introduced in the v0.3.1rc18 release. See also [[#ngx.req.set_body_data|ngx.req.set_body_data]]. From af944b1790da812ab40a0ee000c2d298a8909d28 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sat, 26 Jan 2013 22:43:03 -0800 Subject: [PATCH 0251/2239] fixed the style in t/044-req-body.t. --- t/044-req-body.t | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/t/044-req-body.t b/t/044-req-body.t index 43ed0a5eb6..3fcff302a1 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -953,7 +953,8 @@ a client request body is buffered to a temporary file lua entry thread aborted: runtime error: [string "content_by_lua"]:2: request body not read yet -=== TEST 33: init & append & finish (use default buffer size) + +=== TEST 34: init & append & finish (use default buffer size) --- config location /t { client_body_buffer_size 4; @@ -983,7 +984,7 @@ a client request body is buffered to a temporary file -=== TEST 34: init & append & finish (exceeding the buffer size, proxy) +=== TEST 35: init & append & finish (exceeding the buffer size, proxy) --- config location /t { rewrite_by_lua ' @@ -1028,7 +1029,7 @@ a client request body is buffered to a temporary file -=== TEST 35: init & append & finish (just in buffer, proxy) +=== TEST 36: init & append & finish (just in buffer, proxy) --- config location /t { rewrite_by_lua ' @@ -1057,7 +1058,7 @@ a client request body is buffered to a temporary file -=== TEST 36: init & append & finish (exceeding buffer size, discard on-disk buffer) +=== TEST 37: init & append & finish (exceeding buffer size, discard on-disk buffer) --- config client_header_buffer_size 100; location /t { @@ -1154,7 +1155,7 @@ a client request body is buffered to a temporary file -=== TEST 37: ngx.req.socket + init & append & finish (requests) +=== TEST 38: ngx.req.socket + init & append & finish (requests) --- config location = /t { client_body_buffer_size 1; @@ -1203,7 +1204,7 @@ a client request body is buffered to a temporary file -=== TEST 38: ngx.req.socket + init & append & finish (pipelined requests, small buffer size) +=== TEST 39: ngx.req.socket + init & append & finish (pipelined requests, small buffer size) --- config location = /t { client_body_buffer_size 1; @@ -1257,7 +1258,7 @@ a client request body is buffered to a temporary file -=== TEST 39: ngx.req.socket + init & append & finish (pipelined requests, big buffer size) +=== TEST 40: ngx.req.socket + init & append & finish (pipelined requests, big buffer size) --- config location = /t { client_body_buffer_size 100; @@ -1312,7 +1313,7 @@ a client request body is buffered to a temporary file -=== TEST 40: calling ngx.req.socket after ngx.req.read_body +=== TEST 41: calling ngx.req.socket after ngx.req.read_body --- config location = /t { client_body_buffer_size 100; @@ -1341,7 +1342,7 @@ a client request body is buffered to a temporary file -=== TEST 41: failed to write 100 continue +=== TEST 42: failed to write 100 continue --- config location = /test { content_by_lua ' From bbdb69568219f26a25972f5943f3f712a28090fa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 27 Jan 2013 12:07:23 -0800 Subject: [PATCH 0252/2239] bugfix: for nginx 1.3.9+ compatibility, we return an error while using ngx.req.socket() to read the chunked request body (for now), because chunked support in the downstream cosocket API is still a TODO. --- src/ngx_http_lua_socket_tcp.c | 8 +++++ t/067-req-socket.t | 56 ++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index a4148ce0e9..b625069a41 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -2979,6 +2979,14 @@ ngx_http_lua_req_socket(lua_State *L) "subrequest"); } +#if nginx_version >= 1003009 + if (r->headers_in.chunked) { + lua_pushnil(L); + lua_pushliteral(L, "chunked request bodies not supported yet"); + return 2; + } +#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/t/067-req-socket.t b/t/067-req-socket.t index ec0d1d0956..f67207b98e 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 6); +plan tests => repeat_each() * (blocks() * 3 + 7); our $HtmlDir = html_dir; @@ -573,3 +573,57 @@ failed to receive: closed [] --- no_error_log [error] + + +=== TEST 9: chunked support is still a TODO +--- config + location /t { + content_by_lua ' + local sock, err = ngx.req.socket() + if sock then + ngx.say("got the request socket") + else + ngx.req.read_body() + ngx.say("failed to get the request socket: ", err) + return + end + + for i = 1, 3 do + local data, err, part = sock:receive(5) + if data then + ngx.say("received: ", data) + else + ngx.say("failed to receive: ", err, " [", part, "]") + end + end + '; + } +--- raw_request eval +"POST /t HTTP/1.1\r +Host: localhost\r +Transfer-Encoding: chunked\r +Connection: close\r +\r +b\r +hello world\r +0\r +\r +" +--- stap2 +/* +F(ngx_http_finalize_request) { + if ($r->main->count == 2) { + print_ubacktrace() + } +} +F(ngx_http_free_request) { + print_ubacktrace() +} +*/ +--- response_body +failed to get the request socket: chunked request bodies not supported yet +--- no_error_log +[error] +[alert] +--- skip_nginx: 4: <1.3.9 + From 58506f76226814da6664c6c869a41f7b71a37c77 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 27 Jan 2013 12:11:37 -0800 Subject: [PATCH 0253/2239] added a (passing) test for chunked request body + ngx.req.read_body (for nginx 1.3.9+). --- t/067-req-socket.t | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/t/067-req-socket.t b/t/067-req-socket.t index f67207b98e..d6d2aa0197 100644 --- a/t/067-req-socket.t +++ b/t/067-req-socket.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 7); +plan tests => repeat_each() * (blocks() * 3 + 8); our $HtmlDir = html_dir; @@ -627,3 +627,42 @@ failed to get the request socket: chunked request bodies not supported yet [alert] --- skip_nginx: 4: <1.3.9 + + +=== TEST 10: chunked support in ngx.req.read_body +--- config + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.say(ngx.req.get_body_data()) + '; + } +--- raw_request eval +"POST /t HTTP/1.1\r +Host: localhost\r +Transfer-Encoding: chunked\r +Connection: close\r +\r +b\r +hello world\r +0\r +\r +" +--- stap2 +/* +F(ngx_http_finalize_request) { + if ($r->main->count == 2) { + print_ubacktrace() + } +} +F(ngx_http_free_request) { + print_ubacktrace() +} +*/ +--- response_body +hello world +--- no_error_log +[error] +[alert] +--- skip_nginx: 4: <1.3.9 + From c0f62e590eb59dd8b0e2458212781ef2567f436c Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 27 Jan 2013 14:06:20 -0800 Subject: [PATCH 0254/2239] bugfix: for nginx 1.3.9+, rewrite_by_lua* or access_by_lua* handlers might hang if the request body was read there, because the nginx core now overrites r->write_event_handler to ngx_http_request_empty_handler in its ngx_http_read_client_request_body API. --- src/ngx_http_lua_output.c | 3 +++ src/ngx_http_lua_req_body.c | 7 ++++--- src/ngx_http_lua_rewriteby.c | 5 +++-- src/ngx_http_lua_socket_tcp.c | 18 ++++++++++++++++++ src/ngx_http_lua_socket_udp.c | 6 ++++++ src/ngx_http_lua_subrequest.c | 12 ++++++++++-- src/ngx_http_lua_util.c | 8 ++++++-- t/079-unused-directives.t | 3 ++- 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/ngx_http_lua_output.c b/src/ngx_http_lua_output.c index a2088a44be..cbeb16f07c 100644 --- a/src/ngx_http_lua_output.c +++ b/src/ngx_http_lua_output.c @@ -550,6 +550,9 @@ ngx_http_lua_ngx_flush(lua_State *L) if (ctx->entered_content_phase) { /* mimic ngx_http_set_write_handler */ r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } wev = r->connection->write; diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index d4cdfff44a..f8a609a4b7 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -117,7 +117,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) r->main->count--; #endif - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { ctx->exit_code = rc; ctx->exited = 1; @@ -131,6 +131,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) #if (nginx_version >= 1002006 && nginx_version < 1003000) || \ nginx_version >= 1003009 r->main->count--; + dd("decrement r->main->count: %d", (int) r->main->count); #endif if (rc == NGX_AGAIN) { @@ -163,8 +164,8 @@ ngx_http_lua_req_body_post_read(ngx_http_request_t *r) ngx_http_lua_loc_conf_t *llcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua req body post read"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua req body post read, c:%ud", r->main->count); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index e13c58651c..2f44bc34c2 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -29,8 +29,9 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) return NGX_DECLINED; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua rewrite handler, uri \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua rewrite 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_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index b625069a41..4dc90ab9ea 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -575,6 +575,9 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } return lua_yield(L, 0); @@ -868,6 +871,9 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; @@ -878,6 +884,9 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } return NGX_AGAIN; @@ -1129,6 +1138,9 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; @@ -1694,6 +1706,9 @@ ngx_http_lua_socket_tcp_send(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; @@ -2620,6 +2635,9 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index c77f19a5d2..defcc4d755 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -390,6 +390,9 @@ ngx_http_lua_socket_udp_setpeername(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } return lua_yield(L, 0); @@ -902,6 +905,9 @@ ngx_http_lua_socket_udp_receive(lua_State *L) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 54939185b2..56a724e80b 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -153,6 +153,10 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) return luaL_error(L, "no co ctx found"); } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua location capture, uri:\"%V\" c:%ud", &r->uri, + r->main->count); + 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); @@ -849,8 +853,9 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) return NGX_OK; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run post subrequest handler: rc:%d", rc); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run post subrequest handler, rc:%i c:%ud", rc, + r->main->count); ctx->run_post_subrequest = 1; @@ -877,6 +882,9 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) "lua restoring write event handler"); pr->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + pr->write_event_handler = ngx_http_core_run_phases; } dd("status rc = %d", (int) rc); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 193a84e360..057687c462 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -975,8 +975,9 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r, ngx_pool_t *old_pool = NULL; #endif - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua run thread, top:%d", lua_gettop(L)); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua run thread, top:%d c:%ud", lua_gettop(L), + r->main->count); /* set Lua VM panic handler */ lua_atpanic(L, ngx_http_lua_atpanic); @@ -3170,6 +3171,9 @@ ngx_http_lua_rd_check_broken_connection(ngx_http_request_t *r) if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_http_core_run_phases; } r->write_event_handler(r); diff --git a/t/079-unused-directives.t b/t/079-unused-directives.t index 1fc6d9d668..42117cdf00 100644 --- a/t/079-unused-directives.t +++ b/t/079-unused-directives.t @@ -55,7 +55,7 @@ GET /t --- response_body hello --- error_log -lua rewrite handler, uri "/t" +lua rewrite handler, uri:"/t" lua capture header filter, uri "/t" lua capture body filter, uri "/t" --- no_error_log @@ -65,6 +65,7 @@ lua header filter for user lua code, uri "/t" lua body filter for user lua code, uri "/t" lua log handler, uri "/t" [error] +--- log_level: debug From 7c37f85300d81c264d4990c54f825ad524abcc88 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Sun, 27 Jan 2013 17:58:38 -0800 Subject: [PATCH 0255/2239] updated valgrind.suppress a bit. --- valgrind.suppress | 1 - 1 file changed, 1 deletion(-) diff --git a/valgrind.suppress b/valgrind.suppress index d5f8d5c7ae..bd7a960c5f 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -205,5 +205,4 @@ fun:ngx_http_lua_ngx_echo fun:malloc fun:ngx_alloc fun:ngx_event_process_init - fun:ngx_single_process_cycle } From 85bab3a9e460723848a3e1ef96de405ef069f0d1 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 28 Jan 2013 16:14:15 -0800 Subject: [PATCH 0256/2239] added a (passing) test to ensure that ngx.req.get_body_data can handle request body bufs more than 2. --- src/ngx_http_lua_req_body.c | 1 + t/044-req-body.t | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index f8a609a4b7..140f69a472 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -281,6 +281,7 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L) len = 0; for (; cl; cl = cl->next) { + dd("body chunk len: %d", (int) ngx_buf_size(cl->buf)); len += cl->buf->last - cl->buf->pos; } diff --git a/t/044-req-body.t b/t/044-req-body.t index 3fcff302a1..1e08855f98 100644 --- a/t/044-req-body.t +++ b/t/044-req-body.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 37); +plan tests => repeat_each() * (blocks() * 3 + 38); #no_diff(); no_long_string(); @@ -1361,3 +1361,38 @@ Expect: 100-Continue [error] http finalize request: 500, "/test?" a:1, c:0 + + +=== TEST 43: chunked support in ngx.req.read_body +--- config + location /t { + content_by_lua ' + ngx.req.read_body() + ngx.say(ngx.req.get_body_data()) + '; + } +--- raw_request eval +"POST /t HTTP/1.1\r +Host: localhost\r +Transfer-Encoding: chunked\r +Connection: close\r +\r +5\r +hello\r +1\r +,\r +1\r + \r +5\r +world\r +0\r +\r +" + +--- response_body +hello, world +--- no_error_log +[error] +[alert] +--- skip_nginx: 4: <1.3.9 + From d931db4573dba942a283542aaa77a7e3af3426b7 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 28 Jan 2013 16:37:30 -0800 Subject: [PATCH 0257/2239] bumped version to 0.7.14. --- README | 10 +++++----- README.markdown | 8 ++++---- doc/HttpLuaModule.wiki | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README b/README index 61d345b93a..40f212b819 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.13 - () released on 3 + This document describes ngx_lua v0.7.14 + () released on 28 January 2013. Synopsis @@ -5530,9 +5530,9 @@ Typical Uses equivalents. Nginx Compatibility - The module is compatible with the following versions of Nginx: + The latest module is compatible with the following versions of Nginx: - * 1.3.x (last tested: 1.3.7) + * 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.6) @@ -5759,7 +5759,7 @@ Copyright and License . Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) - . + , CloudFlare Inc. All rights reserved. diff --git a/README.markdown b/README.markdown index 637abdc402..b2a6f2bcff 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.13](https://github.com/chaoslawful/lua-nginx-module/tags) released on 3 January 2013. +This document describes ngx_lua [v0.7.14](https://github.com/chaoslawful/lua-nginx-module/tags) released on 28 January 2013. Synopsis ======== @@ -4887,9 +4887,9 @@ On a ThinkPad T400 2.80 GHz laptop, the Hello World example readily achieves 28k Nginx Compatibility =================== -The module is compatible with the following versions of Nginx: +The latest module is compatible with the following versions of Nginx: -* 1.3.x (last tested: 1.3.7) +* 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.6) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) @@ -5059,7 +5059,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2013, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) . +Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 47dafe895e..9297dfc7c3 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.13] released on 3 January 2013. +This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.7.14] released on 28 January 2013. = Synopsis = @@ -4721,9 +4721,9 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s 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 module is compatible with the following versions of Nginx: +The latest module is compatible with the following versions of Nginx: -* 1.3.x (last tested: 1.3.7) +* 1.3.x (last tested: 1.3.11) * 1.2.x (last tested: 1.2.6) * 1.1.x (last tested: 1.1.5) * 1.0.x (last tested: 1.0.15) @@ -4880,7 +4880,7 @@ This module is licensed under the BSD license. Copyright (C) 2009-2013, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) . +Copyright (C) 2009-2013, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. From e829556764fcae3e993d27fbdc92d84e18e26766 Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 28 Jan 2013 21:37:39 -0800 Subject: [PATCH 0258/2239] massive coding style fixes. --- src/api/ngx_http_lua_api.h | 13 +- src/ddebug.h | 16 +- src/ngx_http_lua_accessby.c | 21 ++- src/ngx_http_lua_accessby.h | 14 +- src/ngx_http_lua_api.c | 7 +- src/ngx_http_lua_args.c | 23 ++- src/ngx_http_lua_bodyfilterby.c | 29 ++-- src/ngx_http_lua_bodyfilterby.h | 26 ++-- src/ngx_http_lua_cache.c | 42 ++--- src/ngx_http_lua_cache.h | 21 ++- src/ngx_http_lua_capturefilter.c | 11 +- src/ngx_http_lua_capturefilter.h | 13 +- src/ngx_http_lua_clfactory.c | 11 +- src/ngx_http_lua_clfactory.h | 18 ++- src/ngx_http_lua_common.h | 15 +- src/ngx_http_lua_consts.c | 10 +- src/ngx_http_lua_contentby.c | 18 ++- src/ngx_http_lua_contentby.h | 15 +- src/ngx_http_lua_control.c | 20 ++- src/ngx_http_lua_control.h | 14 +- src/ngx_http_lua_coroutine.c | 8 + src/ngx_http_lua_coroutine.h | 14 +- src/ngx_http_lua_ctx.c | 18 ++- src/ngx_http_lua_ctx.h | 16 +- src/ngx_http_lua_directive.c | 33 ++-- src/ngx_http_lua_directive.h | 55 +++---- src/ngx_http_lua_exception.c | 9 +- src/ngx_http_lua_exception.h | 26 +++- src/ngx_http_lua_headerfilterby.c | 21 ++- src/ngx_http_lua_headerfilterby.h | 13 +- src/ngx_http_lua_headers.c | 42 +++-- src/ngx_http_lua_headers.h | 14 +- src/ngx_http_lua_headers_in.c | 61 ++++---- src/ngx_http_lua_headers_in.h | 16 +- src/ngx_http_lua_headers_out.c | 64 ++++---- src/ngx_http_lua_headers_out.h | 19 ++- src/ngx_http_lua_initby.c | 18 ++- src/ngx_http_lua_initby.h | 13 +- src/ngx_http_lua_log.c | 19 ++- src/ngx_http_lua_log.h | 14 +- src/ngx_http_lua_logby.c | 19 ++- src/ngx_http_lua_logby.h | 16 +- src/ngx_http_lua_misc.c | 21 ++- src/ngx_http_lua_misc.h | 14 +- src/ngx_http_lua_module.c | 9 +- src/ngx_http_lua_ndk.c | 23 +-- src/ngx_http_lua_ndk.h | 13 +- src/ngx_http_lua_output.h | 14 +- src/ngx_http_lua_pcrefix.c | 11 +- src/ngx_http_lua_pcrefix.h | 15 +- src/ngx_http_lua_phase.c | 7 + src/ngx_http_lua_phase.h | 8 +- src/ngx_http_lua_probe.h | 6 +- src/ngx_http_lua_regex.c | 249 ++++++++++++++++-------------- src/ngx_http_lua_regex.h | 13 +- src/ngx_http_lua_req_body.c | 64 ++++---- src/ngx_http_lua_req_body.h | 14 +- src/ngx_http_lua_req_method.c | 8 + src/ngx_http_lua_req_method.h | 13 +- src/ngx_http_lua_rewriteby.c | 22 ++- src/ngx_http_lua_rewriteby.h | 14 +- src/ngx_http_lua_script.c | 56 ++++--- src/ngx_http_lua_script.h | 13 +- src/ngx_http_lua_setby.c | 15 +- src/ngx_http_lua_setby.h | 13 +- src/ngx_http_lua_shdict.c | 74 ++++----- src/ngx_http_lua_shdict.h | 17 +- src/ngx_http_lua_sleep.c | 11 +- src/ngx_http_lua_sleep.h | 15 +- src/ngx_http_lua_socket_tcp.c | 45 +++--- src/ngx_http_lua_socket_tcp.h | 14 +- src/ngx_http_lua_socket_udp.c | 11 +- src/ngx_http_lua_socket_udp.h | 15 +- src/ngx_http_lua_string.c | 17 +- src/ngx_http_lua_string.h | 14 +- src/ngx_http_lua_subrequest.c | 80 ++++++---- src/ngx_http_lua_subrequest.h | 16 +- src/ngx_http_lua_time.c | 24 ++- src/ngx_http_lua_time.h | 15 +- src/ngx_http_lua_uri.c | 15 +- src/ngx_http_lua_uri.h | 14 +- src/ngx_http_lua_uthread.c | 7 + src/ngx_http_lua_uthread.h | 13 +- src/ngx_http_lua_util.c | 9 +- src/ngx_http_lua_util.h | 16 +- src/ngx_http_lua_variable.c | 15 +- src/ngx_http_lua_variable.h | 14 +- 87 files changed, 1298 insertions(+), 693 deletions(-) diff --git a/src/api/ngx_http_lua_api.h b/src/api/ngx_http_lua_api.h index 2cb6be29ea..bad8a3fb95 100644 --- a/src/api/ngx_http_lua_api.h +++ b/src/api/ngx_http_lua_api.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_API_H -#define NGX_HTTP_LUA_API_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_API_H_INCLUDED_ +#define _NGX_HTTP_LUA_API_H_INCLUDED_ #include @@ -36,5 +42,6 @@ ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); -#endif /* NGX_HTTP_LUA_API_H */ +#endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ddebug.h b/src/ddebug.h index d3c8d104ce..7965252020 100644 --- a/src/ddebug.h +++ b/src/ddebug.h @@ -1,11 +1,17 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef DDEBUG_H -#define DDEBUG_H +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _DDEBUG_H_INCLUDED_ +#define _DDEBUG_H_INCLUDED_ + #include #include + #if defined(DDEBUG) && (DDEBUG) # if (NGX_HAVE_VARIADIC_MACROS) @@ -70,5 +76,7 @@ static void dd(const char *fmt, ...) { #endif -#endif /* DDEBUG_H */ +#endif /* _DDEBUG_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c index 67290dc2c3..5f57af1149 100644 --- a/src/ngx_http_lua_accessby.c +++ b/src/ngx_http_lua_accessby.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include "ngx_http_lua_accessby.h" #include "ngx_http_lua_util.h" @@ -44,7 +50,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) last_ph = &ph[cur_ph->next - 2]; dd("ph cur: %d, ph next: %d", (int) r->phase_handler, - (int) (cur_ph->next - 2)); + (int) (cur_ph->next - 2)); #if 0 if (cur_ph == last_ph) { @@ -111,7 +117,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, - ngx_http_lua_generic_phase_post_read); + ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ @@ -149,8 +155,10 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ 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, llcf->enable_code_cache ? 1 : 0); + llcf->access_src.value.len, + llcf->access_src_key, + "access_by_lua", &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -197,7 +205,7 @@ 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); + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -331,3 +339,4 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DECLINED; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_accessby.h b/src/ngx_http_lua_accessby.h index ed20920bf9..28c9eb28da 100644 --- a/src/ngx_http_lua_accessby.h +++ b/src/ngx_http_lua_accessby.h @@ -1,7 +1,12 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_ACCESSBY_H -#define NGX_HTTP_LUA_ACCESSBY_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -12,5 +17,6 @@ ngx_int_t 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); -#endif /* NGX_HTTP_LUA_ACCESSBY_H */ +#endif /* _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index 6dc503d53b..e0c50cdfb7 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -1,4 +1,8 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + #include "ddebug.h" @@ -77,3 +81,4 @@ ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index d8d616b75d..abb5527c3b 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_args.h" #include "ngx_http_lua_util.h" @@ -22,7 +30,7 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument but seen %d", - lua_gettop(L)); + lua_gettop(L)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); @@ -58,7 +66,7 @@ ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { default: msg = lua_pushfstring(L, "string, number, or table expected, " - "but got %s", luaL_typename(L, 2)); + "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 1, msg); } @@ -170,7 +178,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) if (r->request_body == NULL) { return luaL_error(L, "no request body found; " - "maybe you should turn on lua_need_request_body?"); + "maybe you should turn on lua_need_request_body?"); } if (r->request_body->temp_file) { @@ -240,7 +248,7 @@ ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + NGX_UNESCAPE_URI_COMPONENT); dd("pushing key %.*s", (int) (dst - q), q); @@ -258,7 +266,7 @@ ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); @@ -296,7 +304,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, - "lua hit query args limit %d", max); + "lua hit query args limit %d", max); return 1; } @@ -310,7 +318,7 @@ ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); @@ -361,3 +369,4 @@ ngx_http_lua_inject_req_args_api(lua_State *L) lua_setfield(L, -2, "get_post_args"); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c index 5bd98fbe3a..d9298a5abe 100644 --- a/src/ngx_http_lua_bodyfilterby.c +++ b/src/ngx_http_lua_bodyfilterby.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_bodyfilterby.h" #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" @@ -22,9 +28,7 @@ static void ngx_http_lua_body_filter_by_lua_env(lua_State *L, - ngx_http_request_t *r, ngx_chain_t *in); - - + ngx_http_request_t *r, ngx_chain_t *in); static ngx_http_output_body_filter_pt ngx_http_next_body_filter; @@ -163,8 +167,10 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in) /* load Lua inline script (w/ cache) sp = 1 */ 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, llcf->enable_code_cache ? 1 : 0); + llcf->body_filter_src.value.len, + llcf->body_filter_src_key, + "body_filter_by_lua", &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -172,7 +178,7 @@ ngx_http_lua_body_filter_inline(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 Lua inlined code: %s", err); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -204,12 +210,13 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in) /* Eval nginx variables in code path string first */ if (ngx_http_complex_value(r, &llcf->body_filter_src, &eval_src) - != NGX_OK) { + != NGX_OK) + { return NGX_ERROR; } script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, - eval_src.len); + eval_src.len); if (script_path == NULL) { return NGX_ERROR; @@ -220,7 +227,8 @@ 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->enable_code_cache ? 1 : 0); + llcf->body_filter_src_key, &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -672,3 +680,4 @@ ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, return 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_bodyfilterby.h b/src/ngx_http_lua_bodyfilterby.h index 8aa2834f09..6a4b306d64 100644 --- a/src/ngx_http_lua_bodyfilterby.h +++ b/src/ngx_http_lua_bodyfilterby.h @@ -1,7 +1,11 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_BODYFILTERBY_H -#define NGX_HTTP_LUA_BODYFILTERBY_H +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -11,21 +15,17 @@ extern ngx_http_output_body_filter_pt ngx_http_lua_next_filter_body_filter; ngx_int_t ngx_http_lua_body_filter_init(void); - ngx_int_t ngx_http_lua_body_filter_by_chunk(lua_State *L, - ngx_http_request_t *r, ngx_chain_t *in); - + ngx_http_request_t *r, ngx_chain_t *in); ngx_int_t ngx_http_lua_body_filter_inline(ngx_http_request_t *r, - ngx_chain_t *in); - + ngx_chain_t *in); ngx_int_t ngx_http_lua_body_filter_file(ngx_http_request_t *r, - ngx_chain_t *in); - + ngx_chain_t *in); int 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); -#endif /* NGX_HTTP_LUA_BODYFILTERBY_H */ +#endif /* _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_cache.c b/src/ngx_http_lua_cache.c index 23a1f2c5ce..726d280e34 100644 --- a/src/ngx_http_lua_cache.c +++ b/src/ngx_http_lua_cache.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include #include "ngx_http_lua_common.h" @@ -57,8 +63,8 @@ ngx_http_lua_cache_load_code(lua_State *L, const char *key) } dd("Value associated with given key in code cache table is not code " - "chunk: stack top=%d, top value type=%s\n", - lua_gettop(L), lua_typename(L, -1)); + "chunk: stack top=%d, top value type=%s\n", + lua_gettop(L), lua_typename(L, -1)); /* remove cache table and value from stack */ lua_pop(L, 2); /* sp-=2 */ @@ -115,8 +121,8 @@ 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, char **err, + unsigned enabled) { int rc; @@ -126,17 +132,15 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, ngx_http_lua_clear_package_loaded(L); } - if (ngx_http_lua_cache_load_code(L, (char *) cache_key) - == NGX_OK) - { + if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == 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); + cache_key, lua_gettop(L), (int) src_len, src); return NGX_OK; } dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'", - cache_key, lua_gettop(L), (int) src_len, src); + cache_key, lua_gettop(L), (int) src_len, src); /* 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); @@ -149,6 +153,7 @@ ngx_http_lua_cache_loadbuffer(lua_State *L, const u_char *src, size_t src_len, } else { if (lua_isstring(L, -1)) { *err = (char *) lua_tostring(L, -1); + } else { *err = "syntax error"; } @@ -175,9 +180,8 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, const u_char *cache_key, char **err, unsigned enabled) { int rc; - - u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1]; u_char *p; + u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1]; /* calculate digest of script file path */ dd("code cache enabled: %d", (int) enabled); @@ -190,8 +194,8 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, p = ngx_http_lua_digest_hex(p, script, ngx_strlen(script)); *p = '\0'; - cache_key = buf; + } else { dd("CACHE file key already pre-calculated"); } @@ -201,12 +205,12 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, if (ngx_http_lua_cache_load_code(L, (char *) cache_key) == 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); + cache_key, lua_gettop(L), script); return NGX_OK; } dd("Code cache missed! cache key='%s', stack top=%d, file path='%s'", - cache_key, lua_gettop(L), script); + cache_key, lua_gettop(L), script); } /* load closure factory of script file to the top of lua stack, sp++ */ @@ -220,6 +224,7 @@ ngx_http_lua_cache_loadfile(lua_State *L, const u_char *script, } else { if (lua_isstring(L, -1)) { *err = (char *) lua_tostring(L, -1); + } else { *err = "syntax error"; } @@ -261,9 +266,7 @@ ngx_http_lua_clear_package_loaded(lua_State *L) dd("clear out package.loaded.* on the Lua land"); lua_getglobal(L, "package"); /* package */ - lua_getfield(L, -1, "loaded"); /* package loaded */ - lua_pushnil(L); /* package loaded nil */ while (lua_next(L, -2)) { /* package loaded key value */ @@ -274,8 +277,8 @@ ngx_http_lua_clear_package_loaded(lua_State *L) #if 1 /* XXX work-around the "stack overflow" issue of LuaRocks * while unloading and reloading Lua modules */ - if (len >= sizeof("luarocks") - 1 && - ngx_strncmp(p, "luarocks", sizeof("luarocks") - 1) == 0) + if (len >= sizeof("luarocks") - 1 + && ngx_strncmp(p, "luarocks", sizeof("luarocks") - 1) == 0) { goto done; } @@ -388,3 +391,4 @@ ngx_http_lua_clear_package_loaded(lua_State *L) lua_setglobal(L, "_G"); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_cache.h b/src/ngx_http_lua_cache.h index fe00b7d263..f8c13e903d 100644 --- a/src/ngx_http_lua_cache.h +++ b/src/ngx_http_lua_cache.h @@ -1,17 +1,24 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_CACHE_H -#define NGX_HTTP_LUA_CACHE_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CACHE_H_INCLUDED_ +#define _NGX_HTTP_LUA_CACHE_H_INCLUDED_ + #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, - char **err, unsigned enabled); + 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, char **err, unsigned enabled); -#endif /* NGX_HTTP_LUA_CACHE_H */ +#endif /* _NGX_HTTP_LUA_CACHE_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_capturefilter.c b/src/ngx_http_lua_capturefilter.c index ec4bf66590..a837fb8e08 100644 --- a/src/ngx_http_lua_capturefilter.c +++ b/src/ngx_http_lua_capturefilter.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include "ngx_http_lua_capturefilter.h" #include "ngx_http_lua_util.h" @@ -18,7 +24,7 @@ ngx_http_output_body_filter_pt ngx_http_lua_next_body_filter; static ngx_int_t ngx_http_lua_capture_header_filter(ngx_http_request_t *r); static ngx_int_t ngx_http_lua_capture_body_filter(ngx_http_request_t *r, - ngx_chain_t *in); + ngx_chain_t *in); ngx_int_t @@ -154,3 +160,4 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_capturefilter.h b/src/ngx_http_lua_capturefilter.h index 61eba2a206..1e9d529e91 100644 --- a/src/ngx_http_lua_capturefilter.h +++ b/src/ngx_http_lua_capturefilter.h @@ -1,7 +1,13 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_CAPTUREFILTER_H -#define NGX_HTTP_LUA_CAPTUREFILTER_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_ +#define _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_ + #include "ngx_http_lua_common.h" @@ -11,3 +17,4 @@ ngx_int_t ngx_http_lua_capture_filter_init(ngx_conf_t *cf); #endif /* NGX_HTTP_LUA_CAPTUREFILTER_H */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_clfactory.c b/src/ngx_http_lua_clfactory.c index 8e30d6fbe5..0cc26aac69 100644 --- a/src/ngx_http_lua_clfactory.c +++ b/src/ngx_http_lua_clfactory.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include "ngx_http_lua_clfactory.h" @@ -63,6 +69,7 @@ #define LUAC_HEADERSIZE 12 #define LUAC_VERSION 0x51 + /* * taken from chaoslawful: * Lua Proto @@ -360,6 +367,7 @@ ngx_http_lua_clfactory_bytecode_prepare(lua_State *L, clfactory_file_ctx_t *lf, size_t i = 0; dd("==LJ_END_CODE: %ld rest_len: %ld==", lf->end_code_len, lf->rest_len); + for (i = 0; i < lf->end_code_len; i++) { dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->end_code.ptr[i])); } @@ -784,3 +792,4 @@ clfactory_getS(lua_State *L, void *ud, size_t *size) return ls->s; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_clfactory.h b/src/ngx_http_lua_clfactory.h index 10779fc21e..6029df7174 100644 --- a/src/ngx_http_lua_clfactory.h +++ b/src/ngx_http_lua_clfactory.h @@ -1,7 +1,12 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_CLFACTORY_H -#define NGX_HTTP_LUA_CLFACTORY_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ +#define _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -13,10 +18,13 @@ #define CLFACTORY_END_CODE " end" #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_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); + size_t size, const char *name); + +#endif /* _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ */ -#endif +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index fa53cc1f8a..f9192b7a03 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -1,7 +1,13 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_COMMON_H -#define NGX_HTTP_LUA_COMMON_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_COMMON_H_INCLUDED_ +#define _NGX_HTTP_LUA_COMMON_H_INCLUDED_ + #include #include @@ -394,5 +400,6 @@ extern ngx_http_output_header_filter_pt ngx_http_lua_next_header_filter; extern ngx_http_output_body_filter_pt ngx_http_lua_next_body_filter; -#endif /* NGX_HTTP_LUA_COMMON_H */ +#endif /* _NGX_HTTP_LUA_COMMON_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_consts.c b/src/ngx_http_lua_consts.c index 9ffd43918b..3ff52bb43a 100644 --- a/src/ngx_http_lua_consts.c +++ b/src/ngx_http_lua_consts.c @@ -1,9 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif - #include "ddebug.h" + #include "ngx_http_lua_consts.h" @@ -111,3 +118,4 @@ ngx_http_lua_inject_http_consts(lua_State *L) /* }}} */ } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c index 300935898b..1e0675b427 100644 --- a/src/ngx_http_lua_contentby.c +++ b/src/ngx_http_lua_contentby.c @@ -1,4 +1,9 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 @@ -176,7 +181,7 @@ ngx_http_lua_content_handler(ngx_http_request_t *r) r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, - ngx_http_lua_content_phase_post_read); + ngx_http_lua_content_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ @@ -251,7 +256,7 @@ 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); + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -287,8 +292,10 @@ ngx_http_lua_content_handler_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ 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, llcf->enable_code_cache ? 1 : 0); + llcf->content_src.value.len, + llcf->content_src_key, + "content_by_lua", &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -373,3 +380,4 @@ ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r, return NGX_DONE; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_contentby.h b/src/ngx_http_lua_contentby.h index cd38c8f4f9..349e1d334e 100644 --- a/src/ngx_http_lua_contentby.h +++ b/src/ngx_http_lua_contentby.h @@ -1,7 +1,13 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_CONTENT_BY_H__ -#define NGX_HTTP_LUA_CONTENT_BY_H__ +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ +#define _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ + #include "ngx_http_lua_common.h" @@ -13,5 +19,6 @@ 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); -#endif +#endif /* _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c index 9c25f2bdb1..4c6a0471f5 100644 --- a/src/ngx_http_lua_control.c +++ b/src/ngx_http_lua_control.c @@ -1,3 +1,10 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -59,7 +66,7 @@ ngx_http_lua_ngx_exec(lua_State *L) n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", - n); + n); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); @@ -142,7 +149,7 @@ ngx_http_lua_ngx_exec(lua_State *L) default: msg = lua_pushfstring(L, "string, number, or table expected, " - "but got %s", luaL_typename(L, 2)); + "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } @@ -171,7 +178,7 @@ ngx_http_lua_ngx_exec(lua_State *L) if (ctx->headers_sent) { return luaL_error(L, "attempt to call ngx.exec after " - "sending out response headers"); + "sending out response headers"); } ctx->exec_uri = uri; @@ -211,7 +218,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) rc != NGX_HTTP_MOVED_PERMANENTLY) { return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY and " - "ngx.HTTP_MOVED_PERMANENTLY are allowed"); + "ngx.HTTP_MOVED_PERMANENTLY are allowed"); } } else { rc = NGX_HTTP_MOVED_TEMPORARILY; @@ -239,7 +246,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) if (ctx->headers_sent) { return luaL_error(L, "attempt to call ngx.redirect after sending out " - "the headers"); + "the headers"); } uri = ngx_palloc(r->pool, len); @@ -256,7 +263,7 @@ ngx_http_lua_ngx_redirect(lua_State *L) 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_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); #if 0 dd("location hash: %lu == %lu", @@ -406,3 +413,4 @@ ngx_http_lua_on_abort(lua_State *L) return 1; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_control.h b/src/ngx_http_lua_control.h index 0888cead1f..2c136156fb 100644 --- a/src/ngx_http_lua_control.h +++ b/src/ngx_http_lua_control.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_CONTROL_H -#define NGX_HTTP_LUA_CONTROL_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ +#define _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_control_api(ngx_log_t *log, lua_State *L); -#endif /* NGX_HTTP_LUA_CONTROL_H */ +#endif /* _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ */ +/* 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 21eeb76735..0895bfe28d 100644 --- a/src/ngx_http_lua_coroutine.c +++ b/src/ngx_http_lua_coroutine.c @@ -1,3 +1,10 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -329,3 +336,4 @@ ngx_http_lua_coroutine_status(lua_State *L) return 1; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_coroutine.h b/src/ngx_http_lua_coroutine.h index d2be426d17..8b7bc9057a 100644 --- a/src/ngx_http_lua_coroutine.h +++ b/src/ngx_http_lua_coroutine.h @@ -1,7 +1,12 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_COROUTINE_H -#define NGX_HTTP_LUA_COROUTINE_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ +#define _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -13,5 +18,6 @@ int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx); -#endif /* NGX_HTTP_LUA_COROUTINE_H */ +#endif /* _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ctx.c b/src/ngx_http_lua_ctx.c index b03876b0f8..b591729599 100644 --- a/src/ngx_http_lua_ctx.c +++ b/src/ngx_http_lua_ctx.c @@ -1,8 +1,15 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_util.h" #include "ngx_http_lua_ctx.h" @@ -29,7 +36,7 @@ ngx_http_lua_ngx_get_ctx(lua_State *L) if (ctx->ctx_ref == LUA_NOREF) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua create ngx.ctx table for the current request"); + "lua create ngx.ctx table for the current request"); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -40,7 +47,8 @@ ngx_http_lua_ngx_get_ctx(lua_State *L) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua fetching existing ngx.ctx table for the current request"); + "lua fetching existing ngx.ctx table for the current " + "request"); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -84,7 +92,7 @@ ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, if (ctx->ctx_ref == LUA_NOREF) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua create ngx.ctx table for the current request"); + "lua create ngx.ctx table for the current request"); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -95,7 +103,8 @@ ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua fetching existing ngx.ctx table for the current request"); + "lua fetching existing ngx.ctx table for the current " + "request"); lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); @@ -107,3 +116,4 @@ ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, return 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ctx.h b/src/ngx_http_lua_ctx.h index 84301d9a72..f73f73e5c1 100644 --- a/src/ngx_http_lua_ctx.h +++ b/src/ngx_http_lua_ctx.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_CTX_H -#define NGX_HTTP_LUA_CTX_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_CTX_H_INCLUDED_ +#define _NGX_HTTP_LUA_CTX_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,8 +15,9 @@ int ngx_http_lua_ngx_get_ctx(lua_State *L); int 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); -#endif /* NGX_HTTP_LUA_CTX_H */ +#endif /* _NGX_HTTP_LUA_CTX_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 251431c441..746ded665e 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -1,4 +1,9 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 @@ -74,7 +79,7 @@ ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx->log = &cf->cycle->new_log; zone = ngx_shared_memory_add(cf, &name, (size_t) size, - &ngx_http_lua_module); + &ngx_http_lua_module); if (zone == NULL) { return NGX_CONF_ERROR; } @@ -83,8 +88,8 @@ ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ctx = zone->data; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "lua_shared_dict \"%V\" is already defined as \"%V\"", - &name, &ctx->name); + "lua_shared_dict \"%V\" is already defined as " + "\"%V\"", &name, &ctx->name); return NGX_CONF_ERROR; } @@ -120,7 +125,8 @@ ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (!*fp) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "lua_code_cache is off; this will hurt performance"); + "lua_code_cache is off; this will hurt " + "performance"); } return NGX_CONF_OK; @@ -354,7 +360,7 @@ 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); + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -407,7 +413,7 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -489,7 +495,7 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -572,7 +578,7 @@ ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -660,7 +666,7 @@ ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -742,7 +748,7 @@ ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -823,7 +829,7 @@ ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -902,7 +908,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, if (value[1].len == 0) { /* Oops...Invalid location conf */ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "Invalid location config: no runnable Lua code"); + "invalid location config: no runnable Lua code"); return NGX_CONF_ERROR; } @@ -925,3 +931,4 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_directive.h b/src/ngx_http_lua_directive.h index bd067f8921..e548956050 100644 --- a/src/ngx_http_lua_directive.h +++ b/src/ngx_http_lua_directive.h @@ -1,59 +1,54 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_DIRECTIVE_H -#define NGX_HTTP_LUA_DIRECTIVE_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ +#define _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ + #include "ngx_http_lua_common.h" char * ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - char * ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + void *conf); char * ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if defined(NDK) && NDK char * ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - char * ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - + 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_str_t *val, ngx_http_variable_value_t *v, void *data); 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_str_t *val, ngx_http_variable_value_t *v, void *data); #endif char * ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); + void *conf); + -#endif /* NGX_HTTP_LUA_DIRECTIVE_H */ +#endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_exception.c b/src/ngx_http_lua_exception.c index 7325ff4bad..c1adc0a551 100644 --- a/src/ngx_http_lua_exception.c +++ b/src/ngx_http_lua_exception.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" @@ -45,3 +51,4 @@ ngx_http_lua_atpanic(lua_State *L) return 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_exception.h b/src/ngx_http_lua_exception.h index 7e8be0bff7..a70708a94c 100644 --- a/src/ngx_http_lua_exception.h +++ b/src/ngx_http_lua_exception.h @@ -1,14 +1,25 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_EXCEPTION_H -#define NGX_HTTP_LUA_EXCEPTION_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ +#define _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ #include "ngx_http_lua_common.h" -#define NGX_LUA_EXCEPTION_TRY if (setjmp(ngx_http_lua_exception) == 0) -#define NGX_LUA_EXCEPTION_CATCH else -#define NGX_LUA_EXCEPTION_THROW(x) longjmp(ngx_http_lua_exception, (x)) +#define NGX_LUA_EXCEPTION_TRY \ + if (setjmp(ngx_http_lua_exception) == 0) + +#define NGX_LUA_EXCEPTION_CATCH \ + else + +#define NGX_LUA_EXCEPTION_THROW(x) \ + longjmp(ngx_http_lua_exception, (x)) extern jmp_buf ngx_http_lua_exception; @@ -17,5 +28,6 @@ extern jmp_buf ngx_http_lua_exception; int ngx_http_lua_atpanic(lua_State *L); -#endif /* NGX_HTTP_LUA_EXCEPTION_H */ +#endif /* _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ */ +/* 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 683ef01381..f2a70f9bea 100644 --- a/src/ngx_http_lua_headerfilterby.c +++ b/src/ngx_http_lua_headerfilterby.c @@ -1,4 +1,8 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 @@ -150,8 +154,10 @@ ngx_http_lua_header_filter_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ 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, llcf->enable_code_cache ? 1 : 0); + llcf->header_filter_src.value.len, + llcf->header_filter_src_key, + "header_filter_by_lua", &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -191,12 +197,13 @@ ngx_http_lua_header_filter_file(ngx_http_request_t *r) /* Eval nginx variables in code path string first */ if (ngx_http_complex_value(r, &llcf->header_filter_src, &eval_src) - != NGX_OK) { + != NGX_OK) + { return NGX_ERROR; } script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, - eval_src.len); + eval_src.len); if (script_path == NULL) { return NGX_ERROR; @@ -207,7 +214,8 @@ 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->enable_code_cache ? 1 : 0); + llcf->header_filter_src_key, &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -305,3 +313,4 @@ ngx_http_lua_header_filter_init() return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headerfilterby.h b/src/ngx_http_lua_headerfilterby.h index 083c35e761..822baf7413 100644 --- a/src/ngx_http_lua_headerfilterby.h +++ b/src/ngx_http_lua_headerfilterby.h @@ -1,7 +1,11 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_HEADERFILTERBY_H -#define NGX_HTTP_LUA_HEADERFILTERBY_H +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -20,5 +24,6 @@ ngx_int_t ngx_http_lua_header_filter_inline(ngx_http_request_t *r); ngx_int_t ngx_http_lua_header_filter_file(ngx_http_request_t *r); -#endif /* NGX_HTTP_LUA_HEADERFILTERBY_H */ +#endif /* _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c index 9f593153fd..6ed984e00c 100644 --- a/src/ngx_http_lua_headers.c +++ b/src/ngx_http_lua_headers.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_headers.h" #include "ngx_http_lua_headers_out.h" #include "ngx_http_lua_headers_in.h" @@ -92,7 +100,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { /* stack: table key */ lua_pushlstring(L, (char *) header[i].value.data, - header[i].value.len); /* stack: table key value */ + header[i].value.len); /* stack: table key value */ ngx_http_lua_set_multi_value_table(L, -3); @@ -102,7 +110,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L) { if (max > 0 && ++count == max) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua hit request header limit %d", max); + "lua hit request header limit %d", max); return 1; } @@ -224,8 +232,8 @@ ngx_http_lua_ngx_header_set(lua_State *L) rc = ngx_http_set_content_type(r); if (rc != NGX_OK) { return luaL_error(L, - "failed to set default content type: %d", - (int) rc); + "failed to set default content type: %d", + (int) rc); } ctx->headers_set = 1; @@ -257,12 +265,12 @@ ngx_http_lua_ngx_header_set(lua_State *L) value.len = len; rc = ngx_http_lua_set_output_header(r, key, value, - i == 1 /* override */); + i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, - "failed to set header %s (error: %d)", - key.data, (int) rc); + "failed to set header %s (error: %d)", + key.data, (int) rc); } } @@ -281,13 +289,13 @@ ngx_http_lua_ngx_header_set(lua_State *L) } dd("key: %.*s, value: %.*s", - (int) key.len, key.data, (int) value.len, value.data); + (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", - key.data, (int) rc); + key.data, (int) rc); } return 0; @@ -299,7 +307,7 @@ ngx_http_lua_ngx_req_header_clear(lua_State *L) { if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one arguments, but seen %d", - lua_gettop(L)); + lua_gettop(L)); } lua_pushnil(L); @@ -313,7 +321,7 @@ ngx_http_lua_ngx_req_header_set(lua_State *L) { if (lua_gettop(L) != 2) { return luaL_error(L, "expecting two arguments, but seen %d", - lua_gettop(L)); + lua_gettop(L)); } return ngx_http_lua_ngx_req_header_set_helper(L); @@ -395,12 +403,12 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) value.len = len; rc = ngx_http_lua_set_input_header(r, key, value, - i == 1 /* override */); + i == 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, - "failed to set header %s (error: %d)", - key.data, (int) rc); + "failed to set header %s (error: %d)", + key.data, (int) rc); } } @@ -425,13 +433,13 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) } dd("key: %.*s, value: %.*s", - (int) key.len, key.data, (int) value.len, value.data); + (int) key.len, key.data, (int) value.len, value.data); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc == NGX_ERROR) { return luaL_error(L, "failed to set header %s (error: %d)", - key.data, (int) rc); + key.data, (int) rc); } return 0; @@ -491,7 +499,7 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L) } lua_setfield(L, -2, "__index"); - lua_rawset(L, LUA_REGISTRYINDEX); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h index b086d6fd9f..01cc7bf9e4 100644 --- a/src/ngx_http_lua_headers.h +++ b/src/ngx_http_lua_headers.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_HEADERS_H -#define NGX_HTTP_LUA_HEADERS_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ +#define _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -9,5 +16,6 @@ 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); -#endif /* NGX_HTTP_LUA_HEADERS_H */ +#endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_in.c b/src/ngx_http_lua_headers_in.c index 44b6a003b2..9dd5a83d3c 100644 --- a/src/ngx_http_lua_headers_in.c +++ b/src/ngx_http_lua_headers_in.c @@ -1,11 +1,15 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -/* Copyright (C) agentzh */ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include "ngx_http_lua_headers_in.h" #include "ngx_http_lua_util.h" @@ -16,8 +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, 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_content_length_header(ngx_http_request_t *r, @@ -25,14 +28,14 @@ static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r, 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); + ngx_http_lua_header_val_t *hv, ngx_str_t *value); 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_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l, - ngx_list_part_t *cur, ngx_uint_t i); + ngx_list_part_t *cur, ngx_uint_t i); -static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { +static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), @@ -100,7 +103,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, - ngx_str_t *value) + ngx_str_t *value) { return ngx_http_set_header_helper(r, hv, value, NULL, 0); } @@ -108,8 +111,8 @@ ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, 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, + unsigned no_create) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -138,15 +141,14 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, dd("i: %d, part: %p", (int) i, part); if (h[i].key.len == hv->key.len - && ngx_strncasecmp(h[i].key.data, - hv->key.data, - h[i].key.len) == 0) + && ngx_strncasecmp(h[i].key.data, hv->key.data, h[i].key.len) + == 0) { if (value->len == 0) { h[i].hash = 0; - rc = ngx_http_lua_rm_header_helper( - &r->headers_in.headers, part, i); + rc = ngx_http_lua_rm_header_helper(&r->headers_in.headers, + part, i); if (rc == NGX_OK) { if (output_header) { @@ -213,7 +215,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { ngx_table_elt_t *h, **old; @@ -254,7 +256,7 @@ ngx_http_set_builtin_header(ngx_http_request_t *r, 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 *value) { dd("server new value len: %d", (int) value->len); @@ -266,7 +268,7 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { off_t len; @@ -289,7 +291,7 @@ ngx_http_set_content_length_header(ngx_http_request_t *r, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { r->headers_in.content_length_n = -1; @@ -299,7 +301,7 @@ ngx_http_clear_content_length_header(ngx_http_request_t *r, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { value->len = 0; return ngx_http_set_builtin_header(r, hv, value); @@ -308,7 +310,7 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override) + ngx_str_t value, unsigned override) { ngx_http_lua_header_val_t hv; ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; @@ -326,11 +328,11 @@ ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, for (i = 0; handlers[i].name.len; i++) { if (hv.key.len != handlers[i].name.len - || ngx_strncasecmp(hv.key.data, handlers[i].name.data, - handlers[i].name.len) != 0) + || ngx_strncasecmp(hv.key.data, handlers[i].name.data, + handlers[i].name.len) != 0) { dd("hv key comparison: %s <> %s", handlers[i].name.data, - hv.key.data); + hv.key.data); continue; } @@ -360,21 +362,21 @@ ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, - ngx_uint_t i) + ngx_uint_t i) { ngx_table_elt_t *data; ngx_list_part_t *new, *part; dd("list rm item: part %p, i %d, nalloc %d", cur, (int) i, - (int) l->nalloc); + (int) l->nalloc); data = cur->elts; dd("cur: nelts %d, nalloc %d", (int) cur->nelts, - (int) l->nalloc); + (int) l->nalloc); dd("removing: \"%.*s:%.*s\"", (int) data[i].key.len, data[i].key.data, - (int) data[i].value.len, data[i].value.data); + (int) data[i].value.len, data[i].value.data); if (i == 0) { cur->elts = (char *) cur->elts + l->size; @@ -454,3 +456,4 @@ ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur, return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_in.h b/src/ngx_http_lua_headers_in.h index dddc52d801..5397471591 100644 --- a/src/ngx_http_lua_headers_in.h +++ b/src/ngx_http_lua_headers_in.h @@ -1,7 +1,12 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_HEADERS_IN_H -#define NGX_HTTP_LUA_HEADERS_IN_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ +#define _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ #include @@ -9,8 +14,9 @@ ngx_int_t ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override); + ngx_str_t value, unsigned override); -#endif /* NGX_HTTP_LUA_HEADERS_IN_H */ +#endif /* _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_out.c b/src/ngx_http_lua_headers_out.c index 9512d99e66..e06ebeeda5 100644 --- a/src/ngx_http_lua_headers_out.c +++ b/src/ngx_http_lua_headers_out.c @@ -1,11 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -/* Copyright (C) agentzh */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include #include "ngx_http_lua_headers_out.h" #include "ngx_http_lua_util.h" @@ -20,22 +25,22 @@ static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, 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_builtin_multi_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value); + ngx_http_lua_header_val_t *hv, ngx_str_t *value); static ngx_int_t ngx_http_set_last_modified_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_content_type_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value); + 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_last_modified_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); + ngx_http_lua_header_val_t *hv, ngx_str_t *value); -static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { +static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server), @@ -103,7 +108,7 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { static ngx_int_t ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, - ngx_str_t *value) + ngx_str_t *value) { return ngx_http_set_header_helper(r, hv, value, NULL, 0); } @@ -111,8 +116,8 @@ ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, 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, + unsigned no_create) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -131,6 +136,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, if (part->next == NULL) { break; } + part = part->next; h = part->elts; i = 0; @@ -143,7 +149,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, if (value->len == 0 || matched) { dd("clearing normal header for %.*s", (int) hv->key.len, - hv->key.data); + hv->key.data); h[i].value.len = 0; h[i].hash = 0; @@ -212,7 +218,7 @@ ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { ngx_table_elt_t *h, **old; @@ -248,7 +254,7 @@ ngx_http_set_builtin_header(ngx_http_request_t *r, static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { ngx_array_t *pa; ngx_table_elt_t *ho, **ph; @@ -257,7 +263,8 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset); if (pa->elts == NULL) { - if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) + != NGX_OK) { return NGX_ERROR; } @@ -319,7 +326,7 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r, static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { r->headers_out.content_type_len = value->len; r->headers_out.content_type = *value; @@ -333,7 +340,7 @@ ngx_http_set_content_type_header(ngx_http_request_t *r, static ngx_int_t ngx_http_set_last_modified_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { if (value->len == 0) { return ngx_http_clear_last_modified_header(r, hv, value); @@ -350,7 +357,7 @@ static ngx_int_t ngx_http_set_last_modified_header(ngx_http_request_t *r, static ngx_int_t ngx_http_clear_last_modified_header(ngx_http_request_t *r, - ngx_http_lua_header_val_t *hv, ngx_str_t *value) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { r->headers_out.last_modified_time = -1; @@ -360,7 +367,7 @@ ngx_http_clear_last_modified_header(ngx_http_request_t *r, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { off_t len; @@ -381,7 +388,7 @@ ngx_http_set_content_length_header(ngx_http_request_t *r, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { r->headers_out.content_length_n = -1; @@ -391,7 +398,7 @@ ngx_http_clear_content_length_header(ngx_http_request_t *r, 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) + ngx_http_lua_header_val_t *hv, ngx_str_t *value) { value->len = 0; @@ -401,7 +408,7 @@ ngx_http_clear_builtin_header(ngx_http_request_t *r, ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override) + ngx_str_t value, unsigned override) { ngx_http_lua_header_val_t hv; ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers; @@ -413,16 +420,16 @@ ngx_http_lua_set_output_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++) { if (hv.key.len != handlers[i].name.len - || ngx_strncasecmp(hv.key.data, handlers[i].name.data, - handlers[i].name.len) != 0) + || ngx_strncasecmp(hv.key.data, handlers[i].name.data, + handlers[i].name.len) != 0) { dd("hv key comparison: %s <> %s", handlers[i].name.data, - hv.key.data); + hv.key.data); continue; } @@ -452,7 +459,7 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key) + ngx_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -478,7 +485,7 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, - r->headers_out.content_type.len); + r->headers_out.content_type.len); return 1; } @@ -510,8 +517,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, continue; } - if (h[i].key.len == key->len && ngx_strncasecmp(key->data, - h[i].key.data, h[i].key.len) == 0) + if (h[i].key.len == key->len + && ngx_strncasecmp(key->data, h[i].key.data, h[i].key.len) == 0) { if (!found) { found = 1; @@ -541,3 +548,4 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, return 1; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_headers_out.h b/src/ngx_http_lua_headers_out.h index 23e084f2d5..ef5e6d421c 100644 --- a/src/ngx_http_lua_headers_out.h +++ b/src/ngx_http_lua_headers_out.h @@ -1,18 +1,23 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_HEADERS_OUT_H -#define NGX_HTTP_LUA_HEADERS_OUT_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ +#define _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ -#include #include "ngx_http_lua_common.h" ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, - ngx_str_t value, unsigned override); + ngx_str_t value, unsigned override); int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, - ngx_str_t *key); + ngx_str_t *key); -#endif /* NGX_HTTP_LUA_HEADERS_OUT_H */ +#endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_initby.c b/src/ngx_http_lua_initby.c index 375885caed..8fd0eb6d44 100644 --- a/src/ngx_http_lua_initby.c +++ b/src/ngx_http_lua_initby.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -16,9 +22,9 @@ 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) + lua_State *L) { - int status; + int status; status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, lmcf->init_src.len, "init_by_lua") @@ -30,9 +36,9 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, int ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, - lua_State *L) + lua_State *L) { - int status; + int status; status = luaL_loadfile(L, (char *) lmcf->init_src.data) || ngx_http_lua_do_call(log, L); @@ -67,8 +73,7 @@ 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) { - int status; - int base; + int status, base; base = lua_gettop(L); /* function index */ lua_pushcfunction(L, ngx_http_lua_traceback); /* push traceback function */ @@ -79,3 +84,4 @@ ngx_http_lua_do_call(ngx_log_t *log, lua_State *L) return status; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_initby.h b/src/ngx_http_lua_initby.h index cebbff12c5..ce4851193f 100644 --- a/src/ngx_http_lua_initby.h +++ b/src/ngx_http_lua_initby.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_INITBY_H -#define NGX_HTTP_LUA_INITBY_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_INITBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_INITBY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -12,5 +18,6 @@ int ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L); -#endif /* NGX_HTTP_LUA_INITBY_H */ +#endif /* _NGX_HTTP_LUA_INITBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_log.c b/src/ngx_http_lua_log.c index 18258d0978..3f32531e20 100644 --- a/src/ngx_http_lua_log.c +++ b/src/ngx_http_lua_log.c @@ -1,19 +1,24 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_log.h" #include "ngx_http_lua_util.h" static int ngx_http_lua_print(lua_State *L); static int ngx_http_lua_ngx_log(lua_State *L); - - static int log_wrapper(ngx_log_t *log, const char *ident, - ngx_uint_t level, lua_State *L); - + ngx_uint_t level, lua_State *L); static void ngx_http_lua_inject_log_consts(lua_State *L); @@ -93,7 +98,7 @@ ngx_http_lua_print(lua_State *L) static int log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, - lua_State *L) + lua_State *L) { u_char *buf; u_char *p, *q; @@ -176,7 +181,8 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, default: msg = lua_pushfstring(L, "string, number, boolean, or nil " - "expected, got %s", lua_typename(L, type)); + "expected, got %s", + lua_typename(L, type)); return luaL_argerror(L, i, msg); } } @@ -302,3 +308,4 @@ ngx_http_lua_inject_log_consts(lua_State *L) /* }}} */ } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_log.h b/src/ngx_http_lua_log.h index ceb5f2395d..42f1839473 100644 --- a/src/ngx_http_lua_log.h +++ b/src/ngx_http_lua_log.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_LOG_H -#define NGX_HTTP_LUA_LOG_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_LOG_H_INCLUDED_ +#define _NGX_HTTP_LUA_LOG_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_log_api(lua_State *L); -#endif /* NGX_HTTP_LUA_LOG_H */ +#endif /* _NGX_HTTP_LUA_LOG_H_INCLUDED_ */ +/* 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 d0773d5595..ed3c14beff 100644 --- a/src/ngx_http_lua_logby.c +++ b/src/ngx_http_lua_logby.c @@ -1,8 +1,15 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_directive.h" #include "ngx_http_lua_logby.h" #include "ngx_http_lua_exception.h" @@ -69,7 +76,7 @@ ngx_http_lua_log_handler(ngx_http_request_t *r) ngx_http_lua_ctx_t *ctx; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua log handler, uri \"%V\"", &r->uri); + "lua log handler, uri \"%V\"", &r->uri); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); @@ -135,8 +142,9 @@ 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", &err, llcf->enable_code_cache ? 1 : 0); + llcf->log_src.value.len, + llcf->log_src_key, "log_by_lua", + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -171,7 +179,7 @@ ngx_http_lua_log_handler_file(ngx_http_request_t *r) } script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, - eval_src.len); + eval_src.len); if (script_path == NULL) { return NGX_ERROR; @@ -182,7 +190,7 @@ 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); + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -264,3 +272,4 @@ ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_logby.h b/src/ngx_http_lua_logby.h index 01a941bcad..af8aaaa756 100644 --- a/src/ngx_http_lua_logby.h +++ b/src/ngx_http_lua_logby.h @@ -1,18 +1,22 @@ -#ifndef NGX_HTTP_LUA_LOGBY_H -#define NGX_HTTP_LUA_LOGBY_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ #include "ngx_http_lua_common.h" ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r); - ngx_int_t ngx_http_lua_log_handler_inline(ngx_http_request_t *r); - ngx_int_t ngx_http_lua_log_handler_file(ngx_http_request_t *r); - void ngx_http_lua_inject_logby_ngx_api(ngx_conf_t *cf, lua_State *L); -#endif /* NGX_HTTP_LUA_LOGBY_H */ +#endif /* _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 62e316d3f2..0f9960e409 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_misc.h" #include "ngx_http_lua_ctx.h" #include "ngx_http_lua_util.h" @@ -46,21 +54,21 @@ ngx_http_lua_ngx_get(lua_State *L) dd("ngx get %s", p); - if (len == sizeof("status") - 1 && - ngx_strncmp(p, "status", sizeof("status") - 1) == 0) + if (len == sizeof("status") - 1 + && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { lua_pushnumber(L, (lua_Number) r->headers_out.status); return 1; } - if (len == sizeof("ctx") - 1 && - ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) + if (len == sizeof("ctx") - 1 + && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { return ngx_http_lua_ngx_get_ctx(L); } - if (len == sizeof("is_subrequest") - 1 && - ngx_strncmp(p, "is_subrequest", sizeof("is_subrequest") - 1) == 0) + if (len == sizeof("is_subrequest") - 1 + && ngx_strncmp(p, "is_subrequest", sizeof("is_subrequest") - 1) == 0) { lua_pushboolean(L, r != r->main); return 1; @@ -130,3 +138,4 @@ ngx_http_lua_ngx_set(lua_State *L) return luaL_error(L, "attempt to write to ngx. with the key \"%s\"", p); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_misc.h b/src/ngx_http_lua_misc.h index 3d8c1323cf..8a79b920f4 100644 --- a/src/ngx_http_lua_misc.h +++ b/src/ngx_http_lua_misc.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_MISC_H -#define NGX_HTTP_LUA_MISC_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_MISC_H_INCLUDED_ +#define _NGX_HTTP_LUA_MISC_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_misc_api(lua_State *L); -#endif /* NGX_HTTP_LUA_MISC_H */ +#endif /* _NGX_HTTP_LUA_MISC_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 0f9894a966..b0a1fb469b 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_directive.h" #include "ngx_http_lua_capturefilter.h" #include "ngx_http_lua_contentby.h" @@ -720,3 +726,4 @@ ngx_http_lua_init_vm(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) return NGX_CONF_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ndk.c b/src/ngx_http_lua_ndk.c index 76f135f9fd..ac9e410fca 100644 --- a/src/ngx_http_lua_ndk.c +++ b/src/ngx_http_lua_ndk.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -12,7 +18,7 @@ static ndk_set_var_value_pt ngx_http_lookup_ndk_set_var_directive(u_char *name, - size_t name_len); + size_t name_len); static int ngx_http_lua_ndk_set_var_get(lua_State *L); static int ngx_http_lua_ndk_set_var_set(lua_State *L); static int ngx_http_lua_run_set_var_directive(lua_State *L); @@ -33,21 +39,15 @@ ngx_http_lua_ndk_set_var_get(lua_State *L) if (func == NULL) { return luaL_error(L, "ndk.set_var: directive \"%s\" not found " - "or does not use ndk_set_var_value", - p); - + "or does not use ndk_set_var_value", p); } 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_pushcclosure(L, ngx_http_lua_run_set_var_directive, 2); /* table key key closure */ - lua_rawset(L, 1); /* table key */ - lua_rawget(L, 1); /* table closure */ return 1; @@ -104,7 +104,7 @@ ngx_http_lua_run_set_var_directive(lua_State *L) if (rc != NGX_OK) { return luaL_error(L, "calling directive %s failed with code %d", - p, (int) rc); + p, (int) rc); } lua_pushlstring(L, (char *) res.data, res.len); @@ -115,7 +115,7 @@ ngx_http_lua_run_set_var_directive(lua_State *L) static ndk_set_var_value_pt ngx_http_lookup_ndk_set_var_directive(u_char *name, - size_t name_len) + size_t name_len) { ndk_set_var_t *filter; ngx_uint_t i; @@ -144,7 +144,7 @@ ngx_http_lookup_ndk_set_var_directive(u_char *name, } if (cmd->name.len != name_len - || ngx_strncmp(cmd->name.data, name, name_len) != 0) + || ngx_strncmp(cmd->name.data, name, name_len) != 0) { continue; } @@ -185,3 +185,4 @@ ngx_http_lua_inject_ndk_api(lua_State *L) #endif /* defined(NDK) && NDK */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_ndk.h b/src/ngx_http_lua_ndk.h index 1524be9b7d..8015b5f55f 100644 --- a/src/ngx_http_lua_ndk.h +++ b/src/ngx_http_lua_ndk.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_NDK_H -#define NGX_HTTP_LUA_NDK_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_NDK_H_INCLUDED_ +#define _NGX_HTTP_LUA_NDK_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -10,5 +16,6 @@ void ngx_http_lua_inject_ndk_api(lua_State *L); #endif -#endif /* NGX_HTTP_LUA_NDK_H */ +#endif /* _NGX_HTTP_LUA_NDK_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_output.h b/src/ngx_http_lua_output.h index 72d3845524..5d4975e214 100644 --- a/src/ngx_http_lua_output.h +++ b/src/ngx_http_lua_output.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_OUTPUT_H -#define NGX_HTTP_LUA_OUTPUT_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ +#define _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -16,5 +23,6 @@ ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); -#endif /* NGX_HTTP_LUA_OUTPUT_H */ +#endif /* _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_pcrefix.c b/src/ngx_http_lua_pcrefix.c index 875484c97f..562847a639 100644 --- a/src/ngx_http_lua_pcrefix.c +++ b/src/ngx_http_lua_pcrefix.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_pcrefix.h" #include "stdio.h" @@ -95,5 +103,4 @@ ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool) #endif /* NGX_PCRE */ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ - +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_pcrefix.h b/src/ngx_http_lua_pcrefix.h index dd2a0e2f24..80f29f9e75 100644 --- a/src/ngx_http_lua_pcrefix.h +++ b/src/ngx_http_lua_pcrefix.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_PCREFIX_H -#define NGX_HTTP_LUA_PCREFIX_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ +#define _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -11,6 +18,6 @@ void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool); #endif -#endif /* NGX_HTTP_LUA_PCREFIX_H */ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ +#endif /* _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index fad6e44912..b6a4a201a8 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -80,3 +86,4 @@ ngx_http_lua_inject_phase_api(lua_State *L) lua_setfield(L, -2, "get_phase"); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_phase.h b/src/ngx_http_lua_phase.h index f811932744..dcb670f221 100644 --- a/src/ngx_http_lua_phase.h +++ b/src/ngx_http_lua_phase.h @@ -1,5 +1,5 @@ -#ifndef NGX_HTTP_LUA_PHASE_H -#define NGX_HTTP_LUA_PHASE_H +#ifndef _NGX_HTTP_LUA_PHASE_H_INCLUDED_ +#define _NGX_HTTP_LUA_PHASE_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,4 +8,6 @@ void ngx_http_lua_inject_phase_api(lua_State *L); -#endif /* NGX_HTTP_LUA_PHASE_H */ +#endif /* _NGX_HTTP_LUA_PHASE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_probe.h b/src/ngx_http_lua_probe.h index c10eebf108..37b25002cc 100644 --- a/src/ngx_http_lua_probe.h +++ b/src/ngx_http_lua_probe.h @@ -4,8 +4,8 @@ * https://github.com/agentzh/nginx-devel-utils */ -#ifndef NGX_HTTP_LUA_PROBE_H -#define NGX_HTTP_LUA_PROBE_H +#ifndef _NGX_HTTP_LUA_PROBE_H_INCLUDED_ +#define _NGX_HTTP_LUA_PROBE_H_INCLUDED_ #include @@ -82,4 +82,4 @@ #endif -#endif /* NGX_HTTP_LUA_PROBE_H */ +#endif /* _NGX_HTTP_LUA_PROBE_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_regex.c b/src/ngx_http_lua_regex.c index 310c958076..d1c5af1bb3 100644 --- a/src/ngx_http_lua_regex.c +++ b/src/ngx_http_lua_regex.c @@ -1,8 +1,15 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #if (NGX_PCRE) #include "ngx_http_lua_regex.h" @@ -70,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_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); @@ -86,15 +93,15 @@ 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) \ + pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, 0, \ 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, \ - captures, size, ws, wscount) +#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, \ + captures, size, ws, wscount) static int @@ -127,7 +134,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (nargs != 2 && nargs != 3 && nargs != 4) { return luaL_error(L, "expecting two or three or four arguments, " - "but got %d", nargs); + "but got %d", nargs); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); @@ -161,8 +168,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) } else { msg = lua_pushfstring(L, "bad pos field type in the ctx table " - "argument: %s", - luaL_typename(L, -1)); + "argument: %s", luaL_typename(L, -1)); return luaL_argerror(L, 4, msg); } @@ -200,7 +206,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), - lua_tostring(L, -1)); + lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); @@ -209,13 +215,13 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (re) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache hit for match regex \"%s\" with " - "options \"%s\"", pat.data, opts.data); + "lua regex cache hit for match regex \"%s\" with " + "options \"%s\"", pat.data, opts.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, - re->ncaptures, re->captures); + re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; @@ -233,15 +239,15 @@ ngx_http_lua_ngx_re_match(lua_State *L) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache miss for match regex \"%s\" " - "with options \"%s\"", pat.data, opts.data); + "lua regex cache miss for match regex \"%s\" " + "with options \"%s\"", pat.data, opts.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "lua exceeding regex cache max entries (%i)", - lmcf->regex_cache_max_entries); + "lua exceeding regex cache max entries (%i)", + lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } @@ -262,12 +268,12 @@ ngx_http_lua_ngx_re_match(lua_State *L) re_comp.pool = pool; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua compiling match regex \"%s\" with options \"%s\" " - "(compile once: %d) (dfa mode: %d) (jit mode: %d)", - pat.data, opts.data, - (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, - (flags & NGX_LUA_RE_MODE_DFA) != 0, - (flags & NGX_LUA_RE_MODE_JIT) != 0); + "lua compiling match regex \"%s\" with options \"%s\" " + "(compile once: %d) (dfa mode: %d) (jit mode: %d)", + pat.data, opts.data, + (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, + (flags & NGX_LUA_RE_MODE_DFA) != 0, + (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); @@ -280,7 +286,7 @@ ngx_http_lua_ngx_re_match(lua_State *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); + pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } @@ -300,8 +306,8 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } if (sd != NULL) { @@ -314,7 +320,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); + "pcre JIT compiling result: %d", jitted); } # endif /* !(NGX_DEBUG) */ @@ -368,9 +374,9 @@ ngx_http_lua_ngx_re_match(lua_State *L) if (flags & NGX_LUA_RE_COMPILE_ONCE) { 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); + "lua saving compiled regex (%d captures) into the cache " + "(entries %i)", re_comp.captures, + lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { @@ -425,7 +431,8 @@ 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, NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); + (int) pos, cap, ovecsize, ws, + sizeof(ws)/sizeof(ws[0])); #else /* LUA_HAVE_PCRE_DFA */ @@ -436,13 +443,13 @@ 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); } if (rc == NGX_REGEX_NO_MATCHED) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "regex \"%s\" not matched on string \"%s\" starting from %z", - pat.data, subj.data, pos); + "regex \"%V\" not matched on string \"%V\" starting " + "from %i", &pat, &subj, pos); if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { @@ -459,7 +466,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); + "using \"%s\"", (int) rc, subj.data, pat.data); goto error; } @@ -484,7 +491,7 @@ ngx_http_lua_ngx_re_match(lua_State *L) } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); + cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); } @@ -605,13 +612,13 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) dd("options size: %d", (int) sizeof(re_comp.options)); lua_pushlstring(L, (char *) &re_comp.options, - sizeof(re_comp.options)); /* table regex opts */ + sizeof(re_comp.options)); /* table regex opts */ lua_concat(L, 3); /* table key */ lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), - lua_tostring(L, -1)); + lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); @@ -620,13 +627,13 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (re) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache hit for match regex \"%s\" " - "with options \"%s\"", pat.data, opts.data); + "lua regex cache hit for match regex \"%s\" " + "with options \"%s\"", pat.data, opts.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, - re->ncaptures, re->captures); + re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; @@ -644,15 +651,15 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache miss for match regex \"%s\" " - "with options \"%s\"", pat.data, opts.data); + "lua regex cache miss for match regex \"%s\" " + "with options \"%s\"", pat.data, opts.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "lua exceeding regex cache max entries (%i)", - lmcf->regex_cache_max_entries); + "lua exceeding regex cache max entries (%i)", + lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } @@ -671,12 +678,12 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) re_comp.pool = pool; ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua compiling gmatch regex \"%s\" with options \"%s\" " - "(compile once: %d) (dfa mode: %d) (jit mode: %d)", - pat.data, opts.data, - (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, - (flags & NGX_LUA_RE_MODE_DFA) != 0, - (flags & NGX_LUA_RE_MODE_JIT) != 0); + "lua compiling gmatch regex \"%s\" with options \"%s\" " + "(compile once: %d) (dfa mode: %d) (jit mode: %d)", + pat.data, opts.data, + (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, + (flags & NGX_LUA_RE_MODE_DFA) != 0, + (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); @@ -689,7 +696,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *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); + pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } @@ -709,8 +716,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } if (sd != NULL) { @@ -723,7 +730,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); + "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ @@ -740,8 +747,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } @@ -750,8 +757,8 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); + "your pcre build does not have JIT support and " + "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ @@ -775,9 +782,9 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) if (flags & NGX_LUA_RE_COMPILE_ONCE) { 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); + "lua saving compiled regex (%d captures) into the cache " + "(entries %i)", re_comp.captures, + lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { @@ -785,7 +792,7 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); + re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; @@ -901,7 +908,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) if (r != ctx->request || r->pool != ctx->request->pool) { return luaL_error(L, "attempt to use ngx.re.gmatch iterator in a " - "request that did not create it"); + "request that did not create it"); } dd("regex exec..."); @@ -936,8 +943,8 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(ctx->regex, ctx->regex_sd, &subj, - offset, cap, ctx->captures_len, ws, - NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); + offset, cap, ctx->captures_len, ws, + sizeof(ws)/sizeof(ws[0])); #else /* LUA_HAVE_PCRE_DFA */ msg = "at least pcre 6.0 is required for the DFA mode"; @@ -970,7 +977,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); + (int) rc, subj.data); goto error; } @@ -994,7 +1001,7 @@ ngx_http_lua_ngx_re_gmatch_iterator(lua_State *L) } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); + cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); } @@ -1212,7 +1219,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) default: msg = lua_pushfstring(L, "string, number, or function expected, " - "got %s", lua_typename(L, type)); + "got %s", lua_typename(L, type)); return luaL_argerror(L, 3, msg); } @@ -1266,7 +1273,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), - lua_tostring(L, -1)); + lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); @@ -1275,14 +1282,15 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (re) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache hit for sub regex \"%s\" with options " - "\"%s\" and replace \"%s\"", pat.data, opts.data, - func ? (u_char *) "" : tpl.data); + "lua regex cache hit for sub regex \"%s\" with " + "options \"%s\" and replace \"%s\"", + pat.data, opts.data, + func ? (u_char *) "" : tpl.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, - re->ncaptures, re->captures); + re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; @@ -1301,18 +1309,17 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua regex cache miss for %ssub regex \"%s\" with options " - "\"%s\" and replace \"%s\"", - global ? "g" : "", - pat.data, opts.data, - func ? (u_char *) "" : tpl.data); + "lua regex cache miss for %ssub regex \"%s\" with " + "options \"%s\" and replace \"%s\"", + global ? "g" : "", pat.data, opts.data, + func ? (u_char *) "" : tpl.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "lua exceeding regex cache max entries (%i)", - lmcf->regex_cache_max_entries); + "lua exceeding regex cache max entries (%i)", + lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } @@ -1333,12 +1340,12 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) dd("compiling regex"); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua compiling %ssub regex \"%s\" with options \"%s\" " - "(compile once: %d) (dfa mode: %d) (jit mode: %d)", - global ? "g" : "", pat.data, opts.data, - (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, - (flags & NGX_LUA_RE_MODE_DFA) != 0, - (flags & NGX_LUA_RE_MODE_JIT) != 0); + "lua compiling %ssub regex \"%s\" with options \"%s\" " + "(compile once: %d) (dfa mode: %d) (jit mode: %d)", + global ? "g" : "", pat.data, opts.data, + (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, + (flags & NGX_LUA_RE_MODE_DFA) != 0, + (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); @@ -1351,7 +1358,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) 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); + pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } @@ -1371,8 +1378,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } if (sd != NULL) { @@ -1385,7 +1392,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); + "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ @@ -1402,8 +1409,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", - msg, sd); + "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " + "%s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } @@ -1412,8 +1419,8 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); + "your pcre build does not have JIT support and " + "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ @@ -1481,16 +1488,16 @@ 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_tostring(L, 3)); } } if (flags & NGX_LUA_RE_COMPILE_ONCE) { 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); + "lua saving compiled sub regex (%d captures) into " + "the cache (entries %i)", re_comp.captures, + lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { @@ -1498,7 +1505,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); + re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; @@ -1550,7 +1557,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, NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); + offset, cap, ovecsize, ws, + sizeof(ws)/sizeof(ws[0])); #else /* LUA_HAVE_PCRE_DFA */ @@ -1561,7 +1569,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); } if (rc == NGX_REGEX_NO_MATCHED) { @@ -1570,7 +1578,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); + "using \"%s\"", (int) rc, subj.data, + pat.data); goto error; } @@ -1604,10 +1613,10 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); + cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), - (int) i); + (int) i); } lua_rawseti(L, -2, (int) i); @@ -1632,15 +1641,16 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) default: msg = lua_pushfstring(L, "string or number expected to be " - "returned by the replace function, got %s", - lua_typename(L, type)); + "returned by the replace " + "function, got %s", + lua_typename(L, type)); return luaL_argerror(L, 3, msg); } lua_insert(L, 1); luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], - cap[0] - cp_offset); + cap[0] - cp_offset); luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); @@ -1667,7 +1677,7 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) if (rc != NGX_OK) { msg = lua_pushfstring(L, "failed to eval the template for " - "replacement: \"%s\"", tpl.data); + "replacement: \"%s\"", tpl.data); goto error; } @@ -1694,10 +1704,10 @@ ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) } else { if (offset < (int) subj.len) { dd("adding trailer: %s (len %d)", &subj.data[offset], - (int) (subj.len - offset)); + (int) (subj.len - offset)); luaL_addlstring(&luabuf, (char *) &subj.data[offset], - subj.len - offset); + subj.len - offset); } luaL_pushresult(&luabuf); @@ -1808,15 +1818,16 @@ ngx_lua_regex_compile(ngx_lua_regex_compile_t *rc) if (re == NULL) { if ((size_t) erroff == rc->pattern.len) { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, - "pcre_compile() failed: %s in \"%V\"", - errstr, &rc->pattern) - - rc->err.data; + "pcre_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, - "pcre_compile() failed: %s in \"%V\" at \"%s\"", - errstr, &rc->pattern, rc->pattern.data + erroff) - - rc->err.data; + "pcre_compile() failed: %s in \"%V\" " + "at \"%s\"", errstr, &rc->pattern, + rc->pattern.data + erroff) + - rc->err.data; } return NGX_ERROR; @@ -1925,6 +1936,6 @@ ngx_http_lua_re_collect_named_captures(lua_State *L, u_char *name_table, } } - #endif /* NGX_PCRE */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_regex.h b/src/ngx_http_lua_regex.h index 4f02d07788..f5f8e2f875 100644 --- a/src/ngx_http_lua_regex.h +++ b/src/ngx_http_lua_regex.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_REGEX_H -#define NGX_HTTP_LUA_REGEX_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_REGEX_H_INCLUDED_ +#define _NGX_HTTP_LUA_REGEX_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -11,5 +17,6 @@ void ngx_http_lua_inject_regex_api(lua_State *L); #endif -#endif /* NGX_HTTP_LUA_REGEX_H */ +#endif /* _NGX_HTTP_LUA_REGEX_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_req_body.c b/src/ngx_http_lua_req_body.c index 140f69a472..3a4662bb30 100644 --- a/src/ngx_http_lua_req_body.c +++ b/src/ngx_http_lua_req_body.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -136,7 +142,8 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) if (rc == NGX_AGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua read buffered request body requires I/O interruptions"); + "lua read buffered request body requires I/O " + "interruptions"); ctx->waiting_more_body = 1; ctx->req_body_reader_co_ctx = coctx; @@ -150,7 +157,7 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) /* rc == NGX_OK */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua has read buffered request body in a single run"); + "lua has read buffered request body in a single run"); return 0; } @@ -329,17 +336,16 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L) } dd("XXX file directio: %u, f:%u, m:%u, t:%u, end - pos %d, size %d", - r->request_body->temp_file->file.directio, - r->request_body->bufs->buf->in_file, - r->request_body->bufs->buf->memory, - r->request_body->bufs->buf->temporary, - (int) (r->request_body->bufs->buf->end - - r->request_body->bufs->buf->pos), - (int) ngx_buf_size(r->request_body->bufs->buf) - ); + r->request_body->temp_file->file.directio, + r->request_body->bufs->buf->in_file, + r->request_body->bufs->buf->memory, + r->request_body->bufs->buf->temporary, + (int) (r->request_body->bufs->buf->end - + r->request_body->bufs->buf->pos), + (int) ngx_buf_size(r->request_body->bufs->buf)); lua_pushlstring(L, (char *) r->request_body->temp_file->file.name.data, - r->request_body->temp_file->file.name.len); + r->request_body->temp_file->file.name.len); return 1; } @@ -394,13 +400,13 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); } rb->temp_file = NULL; @@ -414,7 +420,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", - (int) ngx_buf_size(cl->buf)); + (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; @@ -435,7 +441,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", - (int) ngx_buf_size(cl->buf)); + (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; @@ -490,7 +496,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", - (int) value.len, value.data, (int) body.len); + (int) value.len, value.data, (int) body.len); r->headers_in.content_length_n = body.len; @@ -505,7 +511,7 @@ ngx_http_lua_ngx_req_set_body_data(lua_State *L) rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " - "input header"); + "input header"); } } @@ -575,7 +581,7 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); @@ -584,7 +590,7 @@ ngx_http_lua_ngx_req_init_body(lua_State *L) tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); } rb->temp_file = NULL; @@ -696,9 +702,10 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) r = lua_touserdata(L, -1); lua_pop(L, 1); - if (r->request_body == NULL || r->request_body->buf == NULL - || r->request_body->bufs == NULL) { - + if (r->request_body == NULL + || r->request_body->buf == NULL + || r->request_body->bufs == NULL) + { return luaL_error(L, "request_body not initalized"); } @@ -756,7 +763,7 @@ ngx_http_lua_ngx_req_body_finish(lua_State *L) rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " - "input header"); + "input header"); } } @@ -863,7 +870,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", - (int) ngx_buf_size(cl->buf)); + (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; @@ -909,7 +916,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); @@ -918,7 +925,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, - tf->file.name.data); + tf->file.name.data); } } else { @@ -978,7 +985,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) /* register file cleanup hook */ cln = ngx_pool_cleanup_add(r->pool, - sizeof(ngx_pool_cleanup_file_t)); + sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return luaL_error(L, "out of memory"); @@ -1029,7 +1036,7 @@ ngx_http_lua_ngx_req_set_body_file(lua_State *L) rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " - "input header"); + "input header"); } } @@ -1162,3 +1169,4 @@ ngx_http_lua_req_body_cleanup(void *data) r->keepalive = 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_req_body.h b/src/ngx_http_lua_req_body.h index 3ba52b675e..38b0e728e4 100644 --- a/src/ngx_http_lua_req_body.h +++ b/src/ngx_http_lua_req_body.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_REQ_BODY_H -#define NGX_HTTP_LUA_REQ_BODY_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ +#define _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_req_body_api(lua_State *L); -#endif /* NGX_HTTP_LUA_REQ_BODY_H */ +#endif /* _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_req_method.c b/src/ngx_http_lua_req_method.c index d047947373..78e5663826 100644 --- a/src/ngx_http_lua_req_method.c +++ b/src/ngx_http_lua_req_method.c @@ -1,7 +1,14 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif + #include "ddebug.h" #include "ngx_http_lua_req_method.h" #include "ngx_http_lua_subrequest.h" @@ -106,3 +113,4 @@ ngx_http_lua_ngx_req_set_method(lua_State *L) return 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_req_method.h b/src/ngx_http_lua_req_method.h index cf8d5c4875..f8aa1af39a 100644 --- a/src/ngx_http_lua_req_method.h +++ b/src/ngx_http_lua_req_method.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_METHOD_H -#define NGX_HTTP_LUA_METHOD_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_METHOD_H_INCLUDED_ +#define _NGX_HTTP_LUA_METHOD_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +14,6 @@ void ngx_http_lua_inject_req_method_api(lua_State *L); -#endif /* NGX_HTTP_LUA_METHOD_H */ +#endif /* _NGX_HTTP_LUA_METHOD_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c index 2f44bc34c2..bab9fee2e2 100644 --- a/src/ngx_http_lua_rewriteby.c +++ b/src/ngx_http_lua_rewriteby.c @@ -1,4 +1,9 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 @@ -13,7 +18,7 @@ static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L, - ngx_http_request_t *r); + ngx_http_request_t *r); ngx_int_t @@ -114,7 +119,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, - ngx_http_lua_generic_phase_post_read); + ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ @@ -154,8 +159,10 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r) /* load Lua inline script (w/ cache) sp = 1 */ 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, llcf->enable_code_cache ? 1 : 0); + llcf->rewrite_src.value.len, + llcf->rewrite_src_key, + "rewrite_by_lua", &err, + llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -190,7 +197,7 @@ ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r) } script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data, - eval_src.len); + eval_src.len); if (script_path == NULL) { return NGX_ERROR; @@ -201,7 +208,7 @@ 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); + &err, llcf->enable_code_cache ? 1 : 0); if (rc != NGX_OK) { if (err == NULL) { @@ -328,3 +335,4 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) return NGX_DECLINED; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_rewriteby.h b/src/ngx_http_lua_rewriteby.h index e87059c00f..172c295a69 100644 --- a/src/ngx_http_lua_rewriteby.h +++ b/src/ngx_http_lua_rewriteby.h @@ -1,7 +1,12 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_REWRITEBY_H -#define NGX_HTTP_LUA_REWRITEBY_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -12,5 +17,6 @@ ngx_int_t ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r); ngx_int_t ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r); -#endif /* NGX_HTTP_LUA_REWRITEBY_H */ +#endif /* _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_script.c b/src/ngx_http_lua_script.c index cc967941ff..410b77b829 100644 --- a/src/ngx_http_lua_script.c +++ b/src/ngx_http_lua_script.c @@ -1,27 +1,34 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_script.h" static void * ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size); static size_t ngx_http_lua_script_copy_len_code( - ngx_http_lua_script_engine_t *e); + ngx_http_lua_script_engine_t *e); static void ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e); static ngx_int_t ngx_http_lua_script_add_copy_code( - ngx_http_lua_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); + ngx_http_lua_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); static ngx_int_t ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc); 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_compile_t *sc, ngx_uint_t n); static size_t ngx_http_lua_script_copy_capture_len_code( - ngx_http_lua_script_engine_t *e); + ngx_http_lua_script_engine_t *e); static void ngx_http_lua_script_copy_capture_code( - ngx_http_lua_script_engine_t *e); + ngx_http_lua_script_engine_t *e); static ngx_int_t ngx_http_lua_script_done(ngx_http_lua_script_compile_t *sc); static ngx_int_t ngx_http_lua_script_init_arrays( - ngx_http_lua_script_compile_t *sc); + ngx_http_lua_script_compile_t *sc); ngx_int_t @@ -98,8 +105,8 @@ ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv) ngx_int_t ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj, - size_t offset, ngx_int_t count, int *cap, - ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf) + size_t offset, ngx_int_t count, int *cap, + ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf) { size_t len; u_char *p; @@ -182,7 +189,8 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) sc->size += name.len; if (ngx_http_lua_script_add_copy_code(sc, &name, - (i == sc->source->len)) != NGX_OK) + (i == sc->source->len)) + != NGX_OK) { return NGX_ERROR; } @@ -250,8 +258,8 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) if (bracket) { ngx_log_error(NGX_LOG_ERR, sc->log, 0, - "the closing bracket in \"%V\" " - "variable is missing", &name); + "the closing bracket in \"%V\" " + "variable is missing", &name); return NGX_ERROR; } @@ -261,8 +269,10 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) if (!num_var) { ngx_log_error(NGX_LOG_ERR, sc->log, 0, - "attempt to use named capturing variable " - "\"%V\" (named captures not supported yet)", &name); + "attempt to use named capturing variable " + "\"%V\" (named captures not supported yet)", + &name); + return NGX_ERROR; } @@ -301,8 +311,8 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) invalid_variable: ngx_log_error(NGX_LOG_ERR, sc->log, 0, - "lua script: invalid capturing variable name found in \"%V\"", - sc->source); + "lua script: invalid capturing variable name found in \"%V\"", + sc->source); return NGX_ERROR; } @@ -310,7 +320,7 @@ ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc) static ngx_int_t ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, - ngx_str_t *value, ngx_uint_t last) + ngx_str_t *value, ngx_uint_t last) { size_t size, len; ngx_http_lua_script_copy_code_t *code; @@ -318,13 +328,13 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, len = value->len; code = ngx_http_lua_script_add_code(*sc->lengths, - sizeof(ngx_http_lua_script_copy_code_t)); + sizeof(ngx_http_lua_script_copy_code_t)); if (code == NULL) { return NGX_ERROR; } code->code = (ngx_http_lua_script_code_pt) - ngx_http_lua_script_copy_len_code; + ngx_http_lua_script_copy_len_code; code->len = len; size = (sizeof(ngx_http_lua_script_copy_code_t) + len + @@ -339,7 +349,7 @@ ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc, code->len = len; ngx_memcpy((u_char *) code + sizeof(ngx_http_lua_script_copy_code_t), - value->data, value->len); + value->data, value->len); return NGX_OK; } @@ -383,7 +393,7 @@ ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e) static ngx_int_t ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, - ngx_uint_t n) + ngx_uint_t n) { ngx_http_lua_script_copy_capture_code_t *code; @@ -394,11 +404,11 @@ ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc, } code->code = (ngx_http_lua_script_code_pt) - ngx_http_lua_script_copy_capture_len_code; + ngx_http_lua_script_copy_capture_len_code; 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_copy_capture_code_t)); if (code == NULL) { return NGX_ERROR; } @@ -439,6 +449,7 @@ 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_copy_capture_code_t *code; code = (ngx_http_lua_script_copy_capture_code_t *) e->ip; @@ -531,3 +542,4 @@ ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size) return ngx_array_push_n(codes, size); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_script.h b/src/ngx_http_lua_script.h index dc993d7916..35410a2539 100644 --- a/src/ngx_http_lua_script.h +++ b/src/ngx_http_lua_script.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_SCRIPT_H -#define NGX_HTTP_LUA_SCRIPT_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ +#define _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -76,5 +82,6 @@ ngx_int_t ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj, ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf); -#endif /* NGX_HTTP_LUA_SCRIPT_H */ +#endif /* _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_setby.c b/src/ngx_http_lua_setby.c index 08748b0728..4d158da271 100644 --- a/src/ngx_http_lua_setby.c +++ b/src/ngx_http_lua_setby.c @@ -1,10 +1,16 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_setby.h" #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" @@ -21,7 +27,7 @@ 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); + size_t nargs, ngx_http_variable_value_t *args); /* chars whose addresses are used as keys in Lua VM regsitry */ @@ -31,7 +37,7 @@ static char ngx_http_lua_setby_args_key; ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, - ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script) + ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script) { size_t i; ngx_int_t rc; @@ -198,7 +204,7 @@ ngx_http_lua_setby_param_get(lua_State *L) * */ 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) + 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); @@ -239,3 +245,4 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, lua_setfenv(L, -2); /* set new running env for the code closure */ } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_setby.h b/src/ngx_http_lua_setby.h index c2017bf4ad..da71753eaa 100644 --- a/src/ngx_http_lua_setby.h +++ b/src/ngx_http_lua_setby.h @@ -1,16 +1,15 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_SET_BY_H -#define NGX_HTTP_LUA_SET_BY_H +#ifndef _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ +#define _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ #include "ngx_http_lua_common.h" ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, - ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, - ngx_str_t *script); - + ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, + ngx_str_t *script); int ngx_http_lua_setby_param_get(lua_State *L); -#endif /* NGX_HTTP_LUA_SET_BY_H */ +#endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index a61334bf5c..28d83a580a 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -124,8 +130,8 @@ ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, sdn = (ngx_http_lua_shdict_node_t *) &node->color; sdnt = (ngx_http_lua_shdict_node_t *) &temp->color; - p = (ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, - sdnt->key_len) < 0) ? &temp->left : &temp->right; + p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, + sdnt->key_len) < 0 ? &temp->left : &temp->right; } if (*p == sentinel) { @@ -359,7 +365,7 @@ ngx_http_lua_shdict_get(lua_State *L) if (n != 2) { return luaL_error(L, "expecting exactly two arguments, " - "but only seen %d", n); + "but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); @@ -432,8 +438,8 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua number value size found for key %s " - "in shared_dict %s: %lu", key.data, name.data, - (unsigned long) value.len); + "in shared_dict %s: %lu", key.data, name.data, + (unsigned long) value.len); } num = *(lua_Number *) value.data; @@ -448,8 +454,8 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua boolean value size found for key %s " - "in shared_dict %s: %lu", key.data, name.data, - (unsigned long) value.len); + "in shared_dict %s: %lu", key.data, name.data, + (unsigned long) value.len); } c = *value.data; @@ -462,8 +468,8 @@ ngx_http_lua_shdict_get(lua_State *L) ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad value type found for key %s in " - "shared_dict %s: %d", key.data, name.data, - value_type); + "shared_dict %s: %d", key.data, name.data, + value_type); } user_flags = sd->user_flags; @@ -488,7 +494,7 @@ ngx_http_lua_shdict_delete(lua_State *L) if (n != 2) { return luaL_error(L, "expecting 2 arguments, " - "but only seen %d", n); + "but only seen %d", n); } lua_pushnil(L); @@ -509,8 +515,7 @@ ngx_http_lua_shdict_flush_all(lua_State *L) n = lua_gettop(L); if (n != 1) { - return luaL_error(L, "expecting 1 argument, " - "but seen %d", n); + return luaL_error(L, "expecting 1 argument, but seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); @@ -557,8 +562,7 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) n = lua_gettop(L); if (n != 1 && n != 2) { - return luaL_error(L, "expecting 1 or 2 argument(s), " - "but saw %d", n); + return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); @@ -600,9 +604,7 @@ ngx_http_lua_shdict_flush_expired(lua_State *L) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); - ngx_slab_free_locked(ctx->shpool, node); - freed++; if (attempts && freed == attempts) { @@ -767,7 +769,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (n != 3 && n != 4 && n != 5) { return luaL_error(L, "expecting 3, 4 or 5 arguments, " - "but only seen %d", n); + "but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); @@ -788,9 +790,8 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) } if (key.len > 65535) { - return luaL_error(L, - "the key argument is more than 65535 bytes: %d", - (int) key.len); + return luaL_error(L, "the key argument is more than 65535 bytes: %d", + (int) key.len); } hash = ngx_crc32_short(key.data, key.len); @@ -825,8 +826,8 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) default: return luaL_error(L, "unsupported value type for key \"%s\" in " - "shared_dict \"%s\": %s", key.data, name.data, - lua_typename(L, value_type)); + "shared_dict \"%s\": %s", key.data, name.data, + lua_typename(L, value_type)); } if (n >= 4) { @@ -902,8 +903,8 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (value.data && value.len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "lua shared dict set: found old entry and value size matched, " - "reusing it"); + "lua shared dict set: found old entry and value " + "size matched, reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); @@ -913,7 +914,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + exptime * 1000; + + exptime * 1000; } else { sd->expires = 0; @@ -939,8 +940,8 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "lua shared dict set: found old entry bug value size NOT matched, " - "removing it first"); + "lua shared dict set: found old entry bug value size " + "NOT matched, removing it first"); remove: ngx_queue_remove(&sd->queue); @@ -967,7 +968,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "lua shared dict set: creating a new entry"); + "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) @@ -979,8 +980,8 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (node == NULL) { 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); + "lua shared dict set: overriding non-expired items " + "due to memory shortage for entry \"%V\"", &name); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { @@ -1012,7 +1013,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags) if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + exptime * 1000; + + exptime * 1000; } else { sd->expires = 0; @@ -1059,8 +1060,7 @@ ngx_http_lua_shdict_incr(lua_State *L) n = lua_gettop(L); if (n != 3) { - return luaL_error(L, "expecting 3 arguments, " - "but only seen %d", n); + return luaL_error(L, "expecting 3 arguments, but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); @@ -1079,9 +1079,8 @@ ngx_http_lua_shdict_incr(lua_State *L) } if (key.len > 65535) { - return luaL_error(L, - "the key argument is more than 65535 bytes: %d", - (int) key.len); + return luaL_error(L, "the key argument is more than 65535 bytes: %d", + (int) key.len); } hash = ngx_crc32_short(key.data, key.len); @@ -1127,7 +1126,6 @@ ngx_http_lua_shdict_incr(lua_State *L) p = sd->data + key.len; num = *(lua_Number *) p; - num += value; ngx_memcpy(p, (lua_Number *) &num, sizeof(lua_Number)); @@ -1258,6 +1256,7 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) if (part->next == NULL) { break; } + part = part->next; zone = part->elts; i = 0; @@ -1278,3 +1277,4 @@ ngx_http_lua_find_zone(u_char *name_data, size_t name_len) return NULL; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_shdict.h b/src/ngx_http_lua_shdict.h index 096f605f8c..29ea28f94e 100644 --- a/src/ngx_http_lua_shdict.h +++ b/src/ngx_http_lua_shdict.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_SHDICT_H -#define NGX_HTTP_LUA_SHDICT_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +#define _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -35,13 +41,12 @@ typedef struct { ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); - void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); - void ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, - lua_State *L); + lua_State *L); -#endif /* NGX_HTTP_LUA_SHDICT_H */ +#endif /* _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_sleep.c b/src/ngx_http_lua_sleep.c index fb0f769f59..cca9ae2461 100644 --- a/src/ngx_http_lua_sleep.c +++ b/src/ngx_http_lua_sleep.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_util.h" #include "ngx_http_lua_sleep.h" #include "ngx_http_lua_contentby.h" @@ -62,7 +70,7 @@ ngx_http_lua_ngx_sleep(lua_State *L) coctx->sleep.log = r->connection->log; dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, - (int) r->uri.len, r->uri.data); + (int) r->uri.len, r->uri.data); ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); @@ -179,3 +187,4 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) return rc; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_sleep.h b/src/ngx_http_lua_sleep.h index 9009d5e73c..80c79b4b5e 100644 --- a/src/ngx_http_lua_sleep.h +++ b/src/ngx_http_lua_sleep.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_SLEEP_H -#define NGX_HTTP_LUA_SLEEP_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ +#define _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,4 +15,6 @@ void ngx_http_lua_inject_sleep_api(lua_State *L); -#endif /* NGX_HTTP_LUA_SLEEP_H */ +#endif /* _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 4dc90ab9ea..5a5070dafd 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -121,9 +127,9 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "tcp"); { - const char buf[] = "local sock = ngx.socket.tcp()" - " local ok, err = sock:connect(...)" - " if ok then return sock else return nil, err end"; + const char buf[] = "local sock = ngx.socket.tcp()" + " 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"); } @@ -1037,7 +1043,7 @@ ngx_http_lua_socket_tcp_receive(lua_State *L) pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); if (pat.len != 2 || pat.data[0] != '*') { p = (char *) lua_pushfstring(L, "bad pattern argument: %s", - (char *) pat.data); + (char *) pat.data); return luaL_argerror(L, 2, p); } @@ -1384,7 +1390,7 @@ ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, if (rc == NGX_ERROR) { dd("input filter error: ft_type:%d waiting:%d", - (int) u->ft_type, (int) u->waiting); + (int) u->ft_type, (int) u->waiting); ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_ERROR); @@ -1640,8 +1646,8 @@ ngx_http_lua_socket_tcp_send(lua_State *L) default: msg = lua_pushfstring(L, "string, number, boolean, nil, " - "or array table expected, got %s", - lua_typename(L, type)); + "or array table expected, got %s", + lua_typename(L, type)); return luaL_argerror(L, 2, msg); } @@ -3300,8 +3306,8 @@ static int ngx_http_lua_socket_tcp_setkeepalive(lua_State *L) "lua tcp socket connection pool size: %ui", pool_size); size = sizeof(ngx_http_lua_socket_pool_t) + key.len - + sizeof(ngx_http_lua_socket_pool_item_t) - * pool_size; + + sizeof(ngx_http_lua_socket_pool_item_t) + * pool_size; spool = lua_newuserdata(L, size); if (spool == NULL) { @@ -3602,7 +3608,7 @@ ngx_http_lua_socket_keepalive_close_handler(ngx_event_t *ev) spool->active_connections--; dd("keepalive: active connections: %u", - (unsigned) spool->active_connections); + (unsigned) spool->active_connections); if (spool->active_connections == 0) { ngx_http_lua_socket_free_pool(ev->log, spool); @@ -3772,7 +3778,7 @@ ngx_http_lua_socket_push_input_data(ngx_http_request_t *r, last = ngx_copy(last, b->pos, b->last - b->pos); dd("copying input data chunk from %p: \"%.*s\"", cl, - (int) (b->last - b->pos), b->pos); + (int) (b->last - b->pos), b->pos); } lua_pushlstring(L, (char *) p, size); @@ -3881,10 +3887,10 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); new_cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - size, - (ngx_buf_tag_t) - &ngx_http_lua_module); + &ctx->free_recv_bufs, + size, + (ngx_buf_tag_t) + &ngx_http_lua_module); if (new_cl == NULL) { return NGX_ERROR; @@ -3895,10 +3901,10 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, b->last = ngx_copy(b->last, pat, prefix); dd("copy resumed data to %p: %d: \"%.*s\"", - new_cl, (int) (b->last - b->pos), (int) (b->last - b->pos), b->pos); + new_cl, (int) (b->last - b->pos), (int) (b->last - b->pos), b->pos); dd("before resuming data: bufs_in %p, buf_in %p, buf_in next %p", - u->bufs_in, u->buf_in, u->buf_in->next); + u->bufs_in, u->buf_in, u->buf_in->next); ll = &u->bufs_in; for (cl = u->bufs_in; cl->next; cl = cl->next) { @@ -3909,14 +3915,14 @@ static ngx_int_t ngx_http_lua_socket_insert_buffer(ngx_http_request_t *r, new_cl->next = u->buf_in; dd("after resuming data: bufs_in %p, buf_in %p, buf_in next %p", - u->bufs_in, u->buf_in, u->buf_in->next); + u->bufs_in, u->buf_in, u->buf_in->next); #if (DDEBUG) for (cl = u->bufs_in; cl; cl = cl->next) { b = cl->buf; dd("result buf after resuming data: %p: %.*s", cl, - (int) ngx_buf_size(b), b->pos); + (int) ngx_buf_size(b), b->pos); } #endif @@ -4031,3 +4037,4 @@ ngx_http_lua_tcp_socket_cleanup(void *data) ngx_http_lua_socket_tcp_finalize(u->request, u); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index ab30c8b2b3..72fa00d3f4 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_SOCKET_TCP_H -#define NGX_HTTP_LUA_SOCKET_TCP_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ +#define _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -121,9 +127,9 @@ typedef struct { void ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L); - void ngx_http_lua_inject_req_socket_api(lua_State *L); -#endif /* NGX_HTTP_LUA_SOCKET_TCP_H */ +#endif /* _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index defcc4d755..fd386634da 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -748,8 +754,8 @@ ngx_http_lua_socket_udp_send(lua_State *L) default: msg = lua_pushfstring(L, "string, number, boolean, nil, " - "or array table expected, got %s", - lua_typename(L, type)); + "or array table expected, got %s", + lua_typename(L, type)); return luaL_argerror(L, 2, msg); } @@ -1490,3 +1496,4 @@ ngx_http_lua_udp_socket_cleanup(void *data) ngx_http_lua_socket_udp_finalize(u->request, u); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_socket_udp.h b/src/ngx_http_lua_socket_udp.h index b64fcc8c2e..819e36befd 100644 --- a/src/ngx_http_lua_socket_udp.h +++ b/src/ngx_http_lua_socket_udp.h @@ -1,12 +1,18 @@ -#ifndef NGX_HTTP_LUA_SOCKET_UDP_H -#define NGX_HTTP_LUA_SOCKET_UDP_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ +#define _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ #include "ngx_http_lua_common.h" typedef struct ngx_http_lua_socket_udp_upstream_s - ngx_http_lua_socket_udp_upstream_t; + ngx_http_lua_socket_udp_upstream_t; typedef @@ -45,5 +51,6 @@ struct ngx_http_lua_socket_udp_upstream_s { void ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L); -#endif /* NGX_HTTP_LUA_SOCKET_UDP_H */ +#endif /* _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 747ceb2d2d..c95489d46c 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -1,3 +1,10 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -242,7 +249,7 @@ ngx_http_lua_ngx_quote_sql_str(lua_State *L) if (p != dst + dlen) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "ngx.quote_sql_str: buffer error"); + "ngx.quote_sql_str: buffer error"); return NGX_ERROR; } @@ -552,7 +559,7 @@ ngx_http_lua_ngx_crc32_long(lua_State *L) if (lua_gettop(L) != 1) { return luaL_error(L, "expecting one argument, but got %d", - lua_gettop(L)); + lua_gettop(L)); } p = (u_char *) luaL_checklstring(L, 1, &len); @@ -569,7 +576,7 @@ ngx_http_lua_ngx_encode_args(lua_State *L) { if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument but seen %d", - lua_gettop(L)); + lua_gettop(L)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); @@ -633,7 +640,6 @@ ngx_http_lua_ngx_decode_args(lua_State *L) { #if (NGX_OPENSSL) - static int ngx_http_lua_ngx_hmac_sha1(lua_State *L) { @@ -645,7 +651,7 @@ ngx_http_lua_ngx_hmac_sha1(lua_State *L) if (lua_gettop(L) != 2) { return luaL_error(L, "expecting one argument, but got %d", - lua_gettop(L)); + lua_gettop(L)); } sec = (u_char *) luaL_checklstring(L, 1, &lsec); @@ -661,3 +667,4 @@ ngx_http_lua_ngx_hmac_sha1(lua_State *L) } #endif +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_string.h b/src/ngx_http_lua_string.h index 1baecddd44..b54cbdfce8 100644 --- a/src/ngx_http_lua_string.h +++ b/src/ngx_http_lua_string.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_STRING_H -#define NGX_HTTP_LUA_STRING_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_STRING_H_INCLUDED_ +#define _NGX_HTTP_LUA_STRING_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_string_api(lua_State *L); -#endif /* NGX_HTTP_LUA_STRING_H */ +#endif /* _NGX_HTTP_LUA_STRING_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_subrequest.c b/src/ngx_http_lua_subrequest.c index 56a724e80b..b95e365aaf 100644 --- a/src/ngx_http_lua_subrequest.c +++ b/src/ngx_http_lua_subrequest.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_subrequest.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_ctx.h" @@ -29,7 +37,7 @@ ngx_str_t ngx_http_lua_options_method = static ngx_str_t ngx_http_lua_content_length_header_key = - ngx_string("Content-Length"); + ngx_string("Content-Length"); static ngx_int_t ngx_http_lua_set_content_length_header(ngx_http_request_t *r, @@ -162,7 +170,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) sr_bodies_len = nsubreqs * sizeof(ngx_str_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + - sr_bodies_len); + sr_bodies_len); if (p == NULL) { return luaL_error(L, "out of memory"); @@ -194,15 +202,15 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " - "but a %s", - index, lua_typename(L, lua_type(L, -1))); + "but a %s", + index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " - "two arguments", index); + "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ @@ -234,8 +242,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " - "subrequest %d, but got %s", index, - luaL_typename(L, 4)); + "subrequest %d, but got %s", index, + luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); @@ -369,7 +377,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L) if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " - "expected a Lua table", lua_typename(L, type)); + "expected a Lua table", + lua_typename(L, type)); } custom_ctx = 1; @@ -578,7 +587,9 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, sr->request_body = body; rc = ngx_http_lua_set_content_length_header(sr, - body->buf ? ngx_buf_size(body->buf) : 0); + body->buf + ? ngx_buf_size(body->buf) + : 0); if (rc != NGX_OK) { return NGX_ERROR; @@ -626,7 +637,7 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, default: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unsupported HTTP method: %u", (unsigned) method); + "unsupported HTTP method: %u", (unsigned) method); return NGX_ERROR; } @@ -668,7 +679,7 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method, static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, - ngx_array_t *extra_vars) + ngx_array_t *extra_vars) { ngx_http_core_main_conf_t *cmcf; ngx_http_variable_t *v; @@ -758,7 +769,8 @@ ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, vv->len = len; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sr->connection->log, 0, - "variable \"%V\" set to value \"%v\"", &name, vv); + "variable \"%V\" set to value \"%v\"", + &name, vv); continue; } @@ -777,7 +789,7 @@ ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr, static void ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L, - int table, ngx_array_t **varsp) + int table, ngx_array_t **varsp) { ngx_array_t *vars; ngx_keyval_t *var; @@ -805,7 +817,7 @@ ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L, if (lua_type(L, -2) != LUA_TSTRING) { luaL_error(L, "attempt to use a non-string key in the " - "\"vars\" option table"); + "\"vars\" option table"); return; } @@ -1019,7 +1031,8 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) r->headers_in.content_length_n = len; if (ngx_list_init(&r->headers_in.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) != NGX_OK) { + sizeof(ngx_table_elt_t)) != NGX_OK) + { return NGX_ERROR; } @@ -1054,13 +1067,13 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) #if 0 dd("content length hash: %lu == %lu", (unsigned long) h->hash, - ngx_hash_key_lc((u_char *) "Content-Length", - sizeof("Content-Length") - 1)); + ngx_hash_key_lc((u_char *) "Content-Length", + sizeof("Content-Length") - 1)); #endif dd("r content length: %.*s", - (int)r->headers_in.content_length->value.len, - r->headers_in.content_length->value.data); + (int)r->headers_in.content_length->value.len, + r->headers_in.content_length->value.data); pr = r->parent; @@ -1085,9 +1098,9 @@ ngx_http_lua_set_content_length_header(ngx_http_request_t *r, off_t len) i = 0; } - if (header[i].key.len == sizeof("Content-Length") - 1 && - ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", - sizeof("Content-Length") - 1) == 0) + if (header[i].key.len == sizeof("Content-Length") - 1 + && ngx_strncasecmp(header[i].key.data, (u_char *) "Content-Length", + sizeof("Content-Length") - 1) == 0) { continue; } @@ -1130,10 +1143,10 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, for (index = 0; index < coctx->nsubreqs; index++) { dd("summary: reqs %d, subquery %d, pending %d, req %.*s", - (int) coctx->nsubreqs, - (int) index, - (int) coctx->pending_subreqs, - (int) r->uri.len, r->uri.data); + (int) coctx->nsubreqs, + (int) index, + (int) coctx->pending_subreqs, + (int) r->uri.len, r->uri.data); /* {{{ construct ret value */ lua_newtable(co); @@ -1192,7 +1205,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, header[i].key.data); lua_pushlstring(co, (char *) header[i].key.data, - header[i].key.len); /* header key */ + header[i].key.len); /* header key */ lua_pushvalue(co, -1); /* stack: table key key */ /* check if header already exists */ @@ -1202,7 +1215,8 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, lua_pop(co, 1); /* stack: table key */ lua_pushlstring(co, (char *) header[i].value.data, - header[i].value.len); /* stack: table key value */ + header[i].value.len); + /* stack: table key value */ lua_rawset(co, -3); /* stack: table */ @@ -1216,7 +1230,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, lua_rawseti(co, -2, 1); /* stack: table key table */ lua_pushlstring(co, (char *) header[i].value.data, - header[i].value.len); + header[i].value.len); /* stack: table key table value */ lua_rawseti(co, -2, lua_objlen(co, -2) + 1); @@ -1226,7 +1240,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, } else { lua_pushlstring(co, (char *) header[i].value.data, - header[i].value.len); + header[i].value.len); /* stack: table key table value */ lua_rawseti(co, -2, lua_objlen(co, -2) + 1); @@ -1240,7 +1254,7 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, if (sr_headers->content_type.len) { lua_pushliteral(co, "Content-Type"); /* header key */ lua_pushlstring(co, (char *) sr_headers->content_type.data, - sr_headers->content_type.len); /* head key value */ + sr_headers->content_type.len); /* head key value */ lua_rawset(co, -3); /* head */ } @@ -1260,7 +1274,8 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r, if (sr_headers->location && sr_headers->location->value.len) { lua_pushliteral(co, "Location"); /* header key */ lua_pushlstring(co, (char *) sr_headers->location->value.data, - sr_headers->location->value.len); /* head key value */ + sr_headers->location->value.len); + /* head key value */ lua_rawset(co, -3); /* head */ } @@ -1530,3 +1545,4 @@ ngx_http_post_request_to_head(ngx_http_request_t *r) return NGX_OK; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_subrequest.h b/src/ngx_http_lua_subrequest.h index 65ef2d4a99..1358d6067b 100644 --- a/src/ngx_http_lua_subrequest.h +++ b/src/ngx_http_lua_subrequest.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_SUBREQUEST_H -#define NGX_HTTP_LUA_SUBREQUEST_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ +#define _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -7,7 +14,7 @@ void ngx_http_lua_inject_subrequest_api(lua_State *L); ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, - ngx_int_t rc); + ngx_int_t rc); extern ngx_str_t ngx_http_lua_get_method; @@ -25,5 +32,6 @@ typedef struct ngx_http_lua_post_subrequest_data_s { } ngx_http_lua_post_subrequest_data_t; -#endif /* NGX_HTTP_LUA_SUBREQUEST_H */ +#endif /* _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_time.c b/src/ngx_http_lua_time.c index e6522597d6..bdcc44e0a2 100644 --- a/src/ngx_http_lua_time.c +++ b/src/ngx_http_lua_time.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_time.h" #include "ngx_http_lua_util.h" @@ -30,7 +38,7 @@ ngx_http_lua_ngx_today(lua_State *L) ngx_gmtime(now + ngx_cached_time->gmtoff * 60, &tm); ngx_sprintf(buf, "%04d-%02d-%02d", tm.ngx_tm_year, tm.ngx_tm_mon, - tm.ngx_tm_mday); + tm.ngx_tm_mday); lua_pushlstring(L, (char *) buf, sizeof(buf)); @@ -48,8 +56,8 @@ ngx_http_lua_ngx_localtime(lua_State *L) ngx_gmtime(ngx_time() + ngx_cached_time->gmtoff * 60, &tm); ngx_sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", tm.ngx_tm_year, - tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, - tm.ngx_tm_sec); + tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, + tm.ngx_tm_sec); lua_pushlstring(L, (char *) buf, sizeof(buf)); @@ -90,15 +98,14 @@ ngx_http_lua_ngx_update_time(lua_State *L) static int ngx_http_lua_ngx_utctime(lua_State *L) { - ngx_tm_t tm; - - u_char buf[sizeof("2010-11-19 20:56:31") - 1]; + ngx_tm_t tm; + u_char buf[sizeof("2010-11-19 20:56:31") - 1]; ngx_gmtime(ngx_time(), &tm); ngx_sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", tm.ngx_tm_year, - tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, - tm.ngx_tm_sec); + tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, + tm.ngx_tm_sec); lua_pushlstring(L, (char *) buf, sizeof(buf)); @@ -244,3 +251,4 @@ ngx_http_lua_inject_req_time_api(lua_State *L) lua_setfield(L, -2, "start_time"); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_time.h b/src/ngx_http_lua_time.h index db43d139f1..291f784ce8 100644 --- a/src/ngx_http_lua_time.h +++ b/src/ngx_http_lua_time.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_TIME_H -#define NGX_HTTP_LUA_TIME_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_TIME_H_INCLUDED_ +#define _NGX_HTTP_LUA_TIME_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -9,4 +16,6 @@ void ngx_http_lua_inject_time_api(lua_State *L); void ngx_http_lua_inject_req_time_api(lua_State *L); -#endif /* NGX_HTTP_LUA_TIME_H */ +#endif /* _NGX_HTTP_LUA_TIME_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 6fb913d8d0..c6ad239de5 100644 --- a/src/ngx_http_lua_uri.c +++ b/src/ngx_http_lua_uri.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_uri.h" #include "ngx_http_lua_util.h" @@ -52,9 +60,9 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) } dd("rewrite: %d, access: %d, content: %d", - (int) ctx->entered_rewrite_phase, - (int) ctx->entered_access_phase, - (int) ctx->entered_content_phase); + (int) ctx->entered_rewrite_phase, + (int) ctx->entered_access_phase, + (int) ctx->entered_content_phase); ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE); @@ -97,3 +105,4 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L) return 0; } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_uri.h b/src/ngx_http_lua_uri.h index ec1dc8b356..9c6e06615e 100644 --- a/src/ngx_http_lua_uri.h +++ b/src/ngx_http_lua_uri.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_URI_H -#define NGX_HTTP_LUA_URI_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_URI_H_INCLUDED_ +#define _NGX_HTTP_LUA_URI_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_req_uri_api(ngx_log_t *log, lua_State *L); -#endif /* NGX_HTTP_LUA_URI_H */ +#endif /* _NGX_HTTP_LUA_URI_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_uthread.c b/src/ngx_http_lua_uthread.c index 253207629d..9d4398f8a1 100644 --- a/src/ngx_http_lua_uthread.c +++ b/src/ngx_http_lua_uthread.c @@ -1,3 +1,9 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif @@ -182,3 +188,4 @@ ngx_http_lua_uthread_wait(lua_State *L) return lua_yield(L, 0); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_uthread.h b/src/ngx_http_lua_uthread.h index a7ab67a1e5..9c3e2d4173 100644 --- a/src/ngx_http_lua_uthread.h +++ b/src/ngx_http_lua_uthread.h @@ -1,5 +1,11 @@ -#ifndef NGX_HTTP_LUA_UTHREAD_H -#define NGX_HTTP_LUA_UTHREAD_H + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_UTHREAD_H_INCLUDED_ +#define _NGX_HTTP_LUA_UTHREAD_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -25,5 +31,6 @@ void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L); -#endif /* NGX_HTTP_LUA_UTHREAD_H */ +#endif /* _NGX_HTTP_LUA_UTHREAD_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 057687c462..d5f33e1f9c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1,4 +1,9 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + #ifndef DDEBUG #define DDEBUG 0 @@ -3269,3 +3274,5 @@ ngx_http_lua_test_expect(ngx_http_request_t *r) return NGX_ERROR; } + +/* 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 7e3b7f1421..526fa05193 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -1,7 +1,13 @@ -/* vim:set ft=c ts=4 sw=4 et fdm=marker: */ -#ifndef NGX_HTTP_LUA_UTIL_H -#define NGX_HTTP_LUA_UTIL_H +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_UTIL_H_INCLUDED_ +#define _NGX_HTTP_LUA_UTIL_H_INCLUDED_ + #include "ngx_http_lua_common.h" @@ -145,7 +151,6 @@ ngx_int_t ngx_http_lua_check_broken_connection(ngx_http_request_t *r, ngx_event_t *ev); - #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ return luaL_error(L, "attempt to abort with pending subrequests"); \ @@ -176,5 +181,6 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) } -#endif /* NGX_HTTP_LUA_UTIL_H */ +#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 edb5d49adb..98c0c152f1 100644 --- a/src/ngx_http_lua_variable.c +++ b/src/ngx_http_lua_variable.c @@ -1,8 +1,16 @@ + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + #ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" + #include "ngx_http_lua_variable.h" #include "ngx_http_lua_util.h" @@ -76,8 +84,9 @@ ngx_http_lua_var_get(lua_State *L) dd("n = %d, ncaptures = %d", (int) n, (int) r->ncaptures); - if (r->captures == NULL || r->captures_data == NULL || - n >= r->ncaptures) + if (r->captures == NULL + || r->captures_data == NULL + || n >= r->ncaptures) { lua_pushnil(L); return 1; @@ -114,7 +123,6 @@ ngx_http_lua_var_get(lua_State *L) } lua_pushlstring(L, (const char *) vv->data, (size_t) vv->len); - return 1; } @@ -272,3 +280,4 @@ ngx_http_lua_var_set(lua_State *L) lowcase, lowcase); } +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_variable.h b/src/ngx_http_lua_variable.h index 2c0bcebec2..550e4d3888 100644 --- a/src/ngx_http_lua_variable.h +++ b/src/ngx_http_lua_variable.h @@ -1,5 +1,12 @@ -#ifndef NGX_HTTP_LUA_VARIABLE_H -#define NGX_HTTP_LUA_VARIABLE_H + +/* + * Copyright (C) Xiaozhe Wang (chaoslawful) + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ +#define _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ #include "ngx_http_lua_common.h" @@ -8,5 +15,6 @@ void ngx_http_lua_inject_variable_api(lua_State *L); -#endif /* NGX_HTTP_LUA_VARIABLE_H */ +#endif /* _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ */ +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ From 6d4150994bc1e43b2c00cef5f45696f2e043baaa Mon Sep 17 00:00:00 2001 From: "agentzh (Yichun Zhang)" Date: Mon, 11 Feb 2013 12:24:19 -0800 Subject: [PATCH 0259/2239] 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 0260/2239] 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 0261/2239] 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 0262/2239] 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 0263/2239] 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 0264/2239] 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 0265/2239] 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 0266/2239] 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 0267/2239] 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 0268/2239] 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 0269/2239] 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 0270/2239] 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 0271/2239] 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 0272/2239] 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 0273/2239] 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 0274/2239] 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 0275/2239] 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 0276/2239] 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 0277/2239] 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 0278/2239] 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 0279/2239] 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 0280/2239] 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 0281/2239] 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 0282/2239] 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 0283/2239] 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 0284/2239] 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 0285/2239] 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 0286/2239] 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 0287/2239] 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 0288/2239] 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 0289/2239] 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 0290/2239] 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 0291/2239] 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 0292/2239] 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 0293/2239] 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 0294/2239] 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 0295/2239] 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 0296/2239] 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 0297/2239] 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 0298/2239] 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 0299/2239] 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 0300/2239] 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 0301/2239] 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 0302/2239] 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 0303/2239] 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 0304/2239] 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 0305/2239] 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 0306/2239] 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 0307/2239] 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 0308/2239] 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 0309/2239] 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 0310/2239] 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 0311/2239] 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 0312/2239] 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 0313/2239] 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 0314/2239] 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 0315/2239] 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 0316/2239] 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 0317/2239] 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 0318/2239] 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 0319/2239] 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 0320/2239] 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 0321/2239] 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 0322/2239] 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 0323/2239] 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 0324/2239] 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 0325/2239] 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 0326/2239] 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 0327/2239] 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 0328/2239] 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 0329/2239] 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 0330/2239] 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 0331/2239] 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 0332/2239] 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 0333/2239] 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 0334/2239] 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 0335/2239] 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 0336/2239] 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 0337/2239] 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 0338/2239] 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 0339/2239] 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 0340/2239] 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 0341/2239] 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 0342/2239] 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 0343/2239] 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 0344/2239] 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 0345/2239] 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 0346/2239] 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 0347/2239] 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 0348/2239] 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 0349/2239] 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 0350/2239] 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 0351/2239] 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 0352/2239] 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 0353/2239] 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 0354/2239] 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 0355/2239] 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 0356/2239] 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 0357/2239] 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 0358/2239] 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 0359/2239] 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 0360/2239] 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 0361/2239] 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 0362/2239] 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 0363/2239] 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 0364/2239] 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 0365/2239] 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 0366/2239] 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 0367/2239] 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 0368/2239] 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 0369/2239] 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 0370/2239] 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 0371/2239] 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 0372/2239] 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 0373/2239] 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 0374/2239] 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 0375/2239] 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 0376/2239] 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 0377/2239] 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 0378/2239] 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 0379/2239] 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 0380/2239] 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 0381/2239] 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 0382/2239] 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 0383/2239] 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 0384/2239] 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 0385/2239] 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 0386/2239] 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 0387/2239] 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 0388/2239] 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 0389/2239] 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 0390/2239] 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 0391/2239] 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 0392/2239] 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 0393/2239] 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 0394/2239] 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 0395/2239] 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 0396/2239] 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 0397/2239] 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 0398/2239] 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 0399/2239] 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 0400/2239] 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 0401/2239] 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 0402/2239] 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 0403/2239] 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 0404/2239] 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 0405/2239] 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 0406/2239] 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 0407/2239] 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 0408/2239] 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 0409/2239] 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 0410/2239] 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 0411/2239] 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 0412/2239] 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 0413/2239] 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 0414/2239] 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 0415/2239] 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 0416/2239] 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 0417/2239] 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 0418/2239] 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 0419/2239] 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 0420/2239] 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 0421/2239] 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 0422/2239] 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 0423/2239] 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 0424/2239] 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 0425/2239] 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 0426/2239] 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 0427/2239] 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 0428/2239] 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 0429/2239] 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 0430/2239] 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 0431/2239] 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 0432/2239] 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 0433/2239] 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 0434/2239] 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 0435/2239] 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 0436/2239] 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 0437/2239] 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 0438/2239] 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 0439/2239] 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 0440/2239] 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 0441/2239] 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 0442/2239] 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 0443/2239] 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 0444/2239] 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 0445/2239] 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 0446/2239] 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 0447/2239] 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 0448/2239] 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 0449/2239] 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 0450/2239] 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 0451/2239] 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 0452/2239] 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 0453/2239] 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 0454/2239] 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 0455/2239] 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 0456/2239] 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 0457/2239] 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 0458/2239] 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 0459/2239] 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 0460/2239] 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 0461/2239] 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 0462/2239] 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 0463/2239] 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 0464/2239] 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 0465/2239] 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 0466/2239] 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 0467/2239] 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 0468/2239] 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 0469/2239] 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 0470/2239] 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 0471/2239] 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 0472/2239] 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 0473/2239] 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 0474/2239] 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 0475/2239] 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 0476/2239] 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 0477/2239] 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 0478/2239] 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 0479/2239] 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 0480/2239] 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 0481/2239] 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 0482/2239] 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 0483/2239] 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 0484/2239] 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 0485/2239] 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 0486/2239] 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 0487/2239] 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 0488/2239] 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 0489/2239] 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 0490/2239] 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 0491/2239] 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 0492/2239] 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 0493/2239] 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 0494/2239] 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 0495/2239] 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 0496/2239] 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 0497/2239] 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 0498/2239] 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 0499/2239] 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 0500/2239] 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 0501/2239] 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 0502/2239] 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 0503/2239] 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 0504/2239] 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 0505/2239] 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 0506/2239] 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 0507/2239] 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 0508/2239] 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 0509/2239] 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 0510/2239] 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 0511/2239] 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 0512/2239] 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 0513/2239] 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 0514/2239] 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 0515/2239] 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 0516/2239] 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 0517/2239] 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 0518/2239] 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 0519/2239] 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 0520/2239] 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 0521/2239] 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 0522/2239] 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 0523/2239] =?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 0524/2239] 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 0525/2239] 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 0526/2239] 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 0527/2239] 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 0528/2239] 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 0529/2239] 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 0530/2239] 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 0531/2239] 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 0532/2239] 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 0533/2239] 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 0534/2239] 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 0535/2239] 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 0536/2239] 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 0537/2239] 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 0538/2239] 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 0539/2239] 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 0711/2239] 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 0712/2239] 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 0713/2239] 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 0714/2239] 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 0715/2239] 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 0716/2239] 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 0717/2239] 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 0718/2239] 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 0719/2239] 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 0720/2239] 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 0721/2239] 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 0722/2239] 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 0723/2239] 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 0724/2239] 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 0725/2239] 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 0726/2239] 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 0727/2239] 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 0728/2239] 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 0729/2239] 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 0730/2239] 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 0731/2239] 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 0732/2239] 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 0733/2239] 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 0734/2239] 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 0735/2239] 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 0736/2239] 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 0737/2239] 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 0738/2239] 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 0739/2239] 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 0740/2239] 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 0741/2239] 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 0742/2239] 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 0743/2239] 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 0744/2239] 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 0745/2239] 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 0746/2239] 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 0747/2239] 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 0748/2239] 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 0749/2239] 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 0750/2239] 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 0751/2239] 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 0752/2239] 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 0753/2239] 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 0754/2239] 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 0755/2239] 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 0756/2239] 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 0757/2239] 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 0758/2239] 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 0759/2239] 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 0760/2239] 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 0761/2239] 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 0762/2239] 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 0763/2239] 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 0764/2239] 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 0765/2239] 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 0766/2239] 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 0767/2239] 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 0768/2239] 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 0769/2239] 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 0770/2239] 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 0771/2239] 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 0772/2239] 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 0773/2239] 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 0774/2239] 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 0775/2239] 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 0776/2239] 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 0777/2239] 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 0778/2239] 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 0779/2239] 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 0780/2239] 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 0781/2239] 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 0782/2239] 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 0783/2239] 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 0784/2239] 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 0785/2239] 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 0786/2239] 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 0787/2239] 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 0788/2239] 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 0789/2239] 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 0790/2239] 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 0791/2239] 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 0792/2239] 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 0793/2239] 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 0794/2239] 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 0795/2239] 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 0796/2239] 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 0797/2239] 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 0798/2239] 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 0799/2239] 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 0800/2239] 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 0801/2239] 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 0802/2239] 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 0803/2239] 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 0804/2239] 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 0805/2239] 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 0806/2239] 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 0807/2239] 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 0808/2239] 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 0809/2239] 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 0810/2239] 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 0811/2239] 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 0812/2239] 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 0813/2239] 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 0814/2239] 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 0815/2239] 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 0816/2239] 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 0817/2239] 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 0818/2239] 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 0819/2239] 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 0820/2239] 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 0821/2239] 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 0822/2239] 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 0823/2239] 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 0824/2239] =?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 0825/2239] =?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 `