diff --git a/Makefile b/Makefile index a4cdb28..881fd8b 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,9 @@ API_TEMPLATE_TARGETS=$(subst _subsys_,_$(SUBSYS)_, $(patsubst src/subsys/%.tt2, MINI_TT2=util/mini-tt2.pl .PHONY: all -all: $(DESTDIR)/api $(TEMPLATE_TARGETS) $(API_TEMPLATE_TARGETS) $(SUBSYS_TARGETS) - cp src/$(SUBSYS)/* $(DESTDIR) +all: $(DESTDIR)/api $(TEMPLATE_TARGETS) $(API_TEMPLATE_TARGETS) + find src/$(SUBSYS) -type f -name '*.tt2' -exec $(MINI_TT2) -d $(DESTDIR) -s $(SUBSYS) '{}' ';' + $(shell cp src/$(SUBSYS)/*.{h,c} $(DESTDIR)) $(DESTDIR)/api/ngx_http_%: src/subsys/api/ngx_subsys_%.tt2 $(MINI_TT2) -d $(DESTDIR)/api -s http $< diff --git a/src/http/ngx_http_lua_accessby.c b/src/http/ngx_http_lua_accessby.c index f587806..eab179d 100644 --- a/src/http/ngx_http_lua_accessby.c +++ b/src/http/ngx_http_lua_accessby.c @@ -60,7 +60,7 @@ ngx_http_lua_access_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -145,11 +145,6 @@ 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/http/ngx_http_lua_bodyfilterby.c b/src/http/ngx_http_lua_bodyfilterby.c index f3af14c..b1ea034 100644 --- a/src/http/ngx_http_lua_bodyfilterby.c +++ b/src/http/ngx_http_lua_bodyfilterby.c @@ -15,12 +15,9 @@ #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_pcrefix.h" -#include "ngx_http_lua_time.h" #include "ngx_http_lua_log.h" -#include "ngx_http_lua_regex.h" #include "ngx_http_lua_cache.h" #include "ngx_http_lua_headers.h" -#include "ngx_http_lua_variable.h" #include "ngx_http_lua_string.h" #include "ngx_http_lua_misc.h" #include "ngx_http_lua_consts.h" @@ -317,11 +314,7 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_ERROR; } -#if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif &ctx->free_bufs, &ctx->busy_bufs, &out, (ngx_buf_tag_t) &ngx_http_lua_module); diff --git a/src/http/ngx_http_lua_headerfilterby.c b/src/http/ngx_http_lua_headerfilterby.c index a0acd4a..f67e751 100644 --- a/src/http/ngx_http_lua_headerfilterby.c +++ b/src/http/ngx_http_lua_headerfilterby.c @@ -13,12 +13,9 @@ #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_pcrefix.h" -#include "ngx_http_lua_time.h" #include "ngx_http_lua_log.h" -#include "ngx_http_lua_regex.h" #include "ngx_http_lua_cache.h" #include "ngx_http_lua_headers.h" -#include "ngx_http_lua_variable.h" #include "ngx_http_lua_string.h" #include "ngx_http_lua_misc.h" #include "ngx_http_lua_consts.h" diff --git a/src/http/ngx_http_lua_headers.c b/src/http/ngx_http_lua_headers.c index 8c4652d..5d22845 100644 --- a/src/http/ngx_http_lua_headers.c +++ b/src/http/ngx_http_lua_headers.c @@ -20,17 +20,39 @@ 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); -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); -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 void ngx_http_lua_ngx_raw_header_cleanup(void *data); #endif +void +ngx_http_lua_inject_resp_header_api(lua_State *L) +{ + 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(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_set); + lua_setfield(L, -2, "set_header"); +} + + static int ngx_http_lua_ngx_req_http_version(lua_State *L) { @@ -80,7 +102,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) size_t size; ngx_buf_t *b, *first = NULL; ngx_int_t i, j; -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 ngx_buf_t **bb; ngx_chain_t *cl; ngx_http_lua_main_conf_t *lmcf; @@ -101,7 +123,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); #endif @@ -121,7 +143,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("hc->nbusy: %d", (int) hc->nbusy); if (hc->nbusy) { -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos, hc->busy->buf->last, hc->busy->buf->end); #else @@ -163,7 +185,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("size: %d", (int) size); if (hc->nbusy) { -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 if (hc->nbusy > lmcf->busy_buf_ptr_count) { if (lmcf->busy_buf_ptrs) { ngx_free(lmcf->busy_buf_ptrs); @@ -186,7 +208,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) #endif b = NULL; -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 bb = lmcf->busy_buf_ptrs; for (i = hc->nbusy; i > 0; i--) { b = bb[i - 1]; @@ -269,7 +291,7 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) if (hc->nbusy) { -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 bb = lmcf->busy_buf_ptrs; for (i = hc->nbusy - 1; i >= 0; i--) { b = bb[i]; @@ -386,110 +408,6 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } -static int -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; - 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_in.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_lightudata_mask( - headers_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - } - - part = &r->headers_in.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 (raw) { - lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len); - - } else { - lua_pushlstring(L, (char *) header[i].lowcase_key, - header[i].key.len); - } - - /* stack: table key */ - - lua_pushlstring(L, (char *) header[i].value.data, - header[i].value.len); /* stack: table key value */ - - ngx_http_lua_set_multi_value_table(L, -3); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua request header: \"%V: %V\"", - &header[i].key, &header[i].value); - - if (--count == 0) { - return 1; - } - } - - return 1; -} - - static int ngx_http_lua_ngx_resp_get_headers(lua_State *L) { @@ -497,7 +415,6 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_table_elt_t *header; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -505,6 +422,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) int max; int raw = 0; int count = 0; + int truncated = 0; + int extra = 0; n = lua_gettop(L); @@ -534,33 +453,16 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no ctx found"); } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; count = part->nelts; - while (part->next) { + while (part->next != NULL) { 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); + lua_createtable(L, 0, count + 2); if (!raw) { lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( @@ -571,6 +473,7 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) #if 1 if (r->headers_out.content_type.len) { + extra++; lua_pushliteral(L, "content-type"); lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); @@ -580,11 +483,13 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) if (r->headers_out.content_length == NULL && r->headers_out.content_length_n >= 0) { + extra++; lua_pushliteral(L, "content-length"); lua_pushfstring(L, "%d", (int) r->headers_out.content_length_n); lua_rawset(L, -3); } + extra++; lua_pushliteral(L, "connection"); if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { lua_pushliteral(L, "upgrade"); @@ -598,12 +503,21 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) lua_rawset(L, -3); if (r->chunked) { + extra++; lua_pushliteral(L, "transfer-encoding"); lua_pushliteral(L, "chunked"); lua_rawset(L, -3); } #endif + if (max > 0 && count + extra > max) { + truncated = 1; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exceeding response header limit %d > %d", + count + extra, max); + count = max - extra; + } + part = &r->headers_out.headers.part; header = part->elts; @@ -656,225 +570,17 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) "lua response header: \"%V: %V\"", &header[i].key, &header[i].value); - if (--count == 0) { - return 1; + if (--count <= 0) { + break; } - } + } /* for */ - return 1; -} - - -static int -ngx_http_lua_ngx_header_get(lua_State *L) -{ - ngx_http_request_t *r; - u_char *p, c; - ngx_str_t key; - ngx_uint_t i; - size_t len; - ngx_http_lua_loc_conf_t *llcf; - ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - if (ctx == NULL) { - return luaL_error(L, "no ctx found"); + if (truncated) { + lua_pushliteral(L, "truncated"); + return 2; } - 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); - - dd("key: %.*s, len %d", (int) len, p, (int) len); - - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); - if (llcf->transform_underscores_in_resp_headers - && memchr(p, '_', len) != NULL) - { - key.data = (u_char *) lua_newuserdata(L, len); - if (key.data == NULL) { - return luaL_error(L, "no memory"); - } - - /* replace "_" with "-" */ - for (i = 0; i < len; i++) { - c = p[i]; - if (c == '_') { - c = '-'; - } - key.data[i] = c; - } - - } else { - key.data = p; - } - - key.len = len; - - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - - return ngx_http_lua_get_output_header(L, r, &key); -} - - -static int -ngx_http_lua_ngx_header_set(lua_State *L) -{ - ngx_http_request_t *r; - u_char *p; - ngx_str_t key; - ngx_str_t value; - ngx_uint_t i; - size_t len; - ngx_http_lua_ctx_t *ctx; - ngx_int_t rc; - ngx_uint_t n; - ngx_http_lua_loc_conf_t *llcf; - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - 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_request(L, r); - - if (r->header_sent || ctx->header_sent) { - 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 */ - p = (u_char *) luaL_checklstring(L, 2, &len); - - 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, "no 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] = '-'; - } - } - } - - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - return luaL_error(L, - "failed to set default content type: %d", - (int) rc); - } - - ctx->headers_set = 1; - } - - if (lua_type(L, 3) == LUA_TNIL) { - ngx_str_null(&value); - - } else if (lua_type(L, 3) == LUA_TTABLE) { - n = lua_objlen(L, 3); - if (n == 0) { - ngx_str_null(&value); - - } else { - for (i = 1; i <= n; i++) { - dd("header value table index %d", (int) i); - - lua_rawgeti(L, 3, i); - p = (u_char *) luaL_checklstring(L, -1, &len); - - value.data = ngx_palloc(r->pool, len); - if (value.data == NULL) { - return luaL_error(L, "no memory"); - } - - ngx_memcpy(value.data, p, len); - value.len = len; - - rc = ngx_http_lua_set_output_header(r, key, value, - i == 1 /* override */); - - if (rc == NGX_ERROR) { - return luaL_error(L, - "failed to set header %s (error: %d)", - key.data, (int) rc); - } - } - - return 0; - } - - } else { - p = (u_char *) luaL_checklstring(L, 3, &len); - value.data = ngx_palloc(r->pool, len); - if (value.data == NULL) { - return luaL_error(L, "no memory"); - } - - ngx_memcpy(value.data, p, len); - value.len = len; - } - - dd("key: %.*s, value: %.*s", - (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); - } - - return 0; -} - - -static int -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_pushnil(L); - - return ngx_http_lua_ngx_req_header_set_helper(L); + return 1; } @@ -1010,49 +716,6 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) } -void -ngx_http_lua_inject_resp_header_api(lua_State *L) -{ - lua_newtable(L); /* .header */ - - lua_createtable(L, 0, 2); /* metatable for .header */ - lua_pushcfunction(L, ngx_http_lua_ngx_header_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ngx_http_lua_ngx_header_set); - lua_setfield(L, -2, "__newindex"); - 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(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"); - - lua_pushcfunction(L, ngx_http_lua_ngx_req_header_set); - lua_setfield(L, -2, "set_header"); - - lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers); - lua_setfield(L, -2, "get_headers"); -} - - void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) { @@ -1084,9 +747,9 @@ ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L) } -#ifndef NGX_LUA_NO_FFI_API int -ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max) +ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max, + int *truncated) { int count; ngx_list_part_t *part; @@ -1095,21 +758,26 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max) return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } + *truncated = 0; + if (max < 0) { max = NGX_HTTP_LUA_MAX_HEADERS; } part = &r->headers_in.headers.part; count = part->nelts; - while (part->next) { + while (part->next != NULL) { part = part->next; count += part->nelts; } if (max > 0 && count > max) { + *truncated = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua exceeding request header limit %d > %d", count, + max); count = max; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "lua exceeding request header limit %d", max); } return count; @@ -1169,7 +837,8 @@ ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, int ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, size_t key_len, int is_nil, const u_char *sval, size_t sval_len, - ngx_http_lua_ffi_str_t *mvals, size_t mvals_len, char **errmsg) + ngx_http_lua_ffi_str_t *mvals, size_t mvals_len, int override, + char **errmsg) { u_char *p; ngx_str_t value, key; @@ -1216,15 +885,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, } } - if (!ctx->headers_set) { - rc = ngx_http_lua_set_content_type(r); - if (rc != NGX_OK) { - *errmsg = "failed to set default content type"; - return NGX_ERROR; - } - - ctx->headers_set = 1; - } + ctx->headers_set = 1; if (is_nil) { value.data = NULL; @@ -1251,8 +912,8 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, ngx_memcpy(value.data, p, len); value.len = len; - rc = ngx_http_lua_set_output_header(r, key, value, - i == 0 /* override */); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, + override && i == 0); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1277,7 +938,7 @@ ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const u_char *key_data, dd("key: %.*s, value: %.*s", (int) key.len, key.data, (int) value.len, value.data); - rc = ngx_http_lua_set_output_header(r, key, value, 1 /* override */); + rc = ngx_http_lua_set_output_header(r, ctx, key, value, override); if (rc == NGX_ERROR) { *errmsg = "failed to set header"; @@ -1345,7 +1006,8 @@ ngx_http_lua_ffi_req_header_set_single_value(ngx_http_request_t *r, int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const u_char *key, size_t key_len, - u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues) + u_char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, + char **errmsg) { int found; u_char c, *p; @@ -1362,19 +1024,10 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { - /* *errmsg = "no ctx found"; */ + *errmsg = "no ctx found"; return NGX_ERROR; } - if (!ctx->headers_set) { - if (ngx_http_lua_set_content_type(r) != NGX_OK) { - /* *errmsg = "failed to set default content type"; */ - return NGX_ERROR; - } - - ctx->headers_set = 1; - } - llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1400,6 +1053,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, { p = ngx_palloc(r->pool, NGX_OFF_T_LEN); if (p == NULL) { + *errmsg = "no memory"; return NGX_ERROR; } @@ -1413,8 +1067,8 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key_buf, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { values[0].data = r->headers_out.content_type.data; values[0].len = r->headers_out.content_type.len; @@ -1482,10 +1136,9 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, return found; } -#endif /* NGX_LUA_NO_FFI_API */ -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 void ngx_http_lua_ngx_raw_header_cleanup(void *data) { diff --git a/src/http/ngx_http_lua_headers.h b/src/http/ngx_http_lua_headers.h index ee4d21c..da9290e 100644 --- a/src/http/ngx_http_lua_headers.h +++ b/src/http/ngx_http_lua_headers.h @@ -15,7 +15,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_create_headers_metatable(ngx_log_t *log, lua_State *L); -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 void ngx_http_lua_ngx_raw_header_cleanup(void *data); #endif diff --git a/src/http/ngx_http_lua_headers_in.c b/src/http/ngx_http_lua_headers_in.c index 4852b2f..4a5a5b6 100644 --- a/src/http/ngx_http_lua_headers_in.c +++ b/src/http/ngx_http_lua_headers_in.c @@ -56,13 +56,10 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, if_modified_since), ngx_http_set_builtin_header }, -#if defined(nginx_version) && nginx_version >= 9002 { ngx_string("If-Unmodified-Since"), offsetof(ngx_http_headers_in_t, if_unmodified_since), ngx_http_set_builtin_header }, -#endif -#if defined(nginx_version) && nginx_version >= 1003003 { ngx_string("If-Match"), offsetof(ngx_http_headers_in_t, if_match), ngx_http_set_builtin_header }, @@ -70,7 +67,6 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { { ngx_string("If-None-Match"), offsetof(ngx_http_headers_in_t, if_none_match), ngx_http_set_builtin_header }, -#endif { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), @@ -104,11 +100,9 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_in_t, expect), ngx_http_set_builtin_header }, -#if defined(nginx_version) && nginx_version >= 1003013 { ngx_string("Upgrade"), offsetof(ngx_http_headers_in_t, upgrade), ngx_http_set_builtin_header }, -#endif #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), @@ -432,10 +426,14 @@ 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; + ngx_str_t host; + ngx_http_lua_main_conf_t *lmcf; + ngx_http_variable_value_t *var; dd("server new value len: %d", (int) value->len); + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); + if (value->len) { host= *value; @@ -449,6 +447,10 @@ ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, r->headers_in.server = *value; } + var = &r->variables[lmcf->host_var_index]; + var->valid = 0; + var->not_found = 0; + return ngx_http_set_builtin_header(r, hv, value); } diff --git a/src/http/ngx_http_lua_headers_out.c b/src/http/ngx_http_lua_headers_out.c index b908eae..cf94bd0 100644 --- a/src/http/ngx_http_lua_headers_out.c +++ b/src/http/ngx_http_lua_headers_out.c @@ -106,6 +106,12 @@ static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = { offsetof(ngx_http_headers_out_t, cache_control), ngx_http_set_builtin_multi_header }, +#if defined(nginx_version) && nginx_version >= 1013009 + { ngx_string("Link"), + offsetof(ngx_http_headers_out_t, link), + ngx_http_set_builtin_multi_header }, +#endif + { ngx_null_string, 0, ngx_http_set_header } }; @@ -476,8 +482,8 @@ 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_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, + ngx_str_t key, 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; @@ -508,6 +514,10 @@ ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, hv.offset = handlers[i].offset; hv.handler = handlers[i].handler; + if (hv.handler == ngx_http_set_content_type_header) { + ctx->mime_set = 1; + } + break; } @@ -528,7 +538,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_http_lua_ctx_t *ctx, ngx_str_t *key) { ngx_table_elt_t *h; ngx_list_part_t *part; @@ -550,8 +560,8 @@ ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, break; case 12: - if (r->headers_out.content_type.len - && ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0) + if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0 + && r->headers_out.content_type.len) { lua_pushlstring(L, (char *) r->headers_out.content_type.data, r->headers_out.content_type.len); diff --git a/src/http/ngx_http_lua_headers_out.h b/src/http/ngx_http_lua_headers_out.h index ef5e6d4..6ec1fe3 100644 --- a/src/http/ngx_http_lua_headers_out.h +++ b/src/http/ngx_http_lua_headers_out.h @@ -12,10 +12,10 @@ #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_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, + ngx_http_lua_ctx_t *ctx, ngx_str_t key, 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_http_lua_ctx_t *ctx, ngx_str_t *key); #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ diff --git a/src/http/ngx_http_lua_ndk.c b/src/http/ngx_http_lua_ndk.c index 6344183..5daeeeb 100644 --- a/src/http/ngx_http_lua_ndk.c +++ b/src/http/ngx_http_lua_ndk.c @@ -19,93 +19,20 @@ static ndk_set_var_value_pt ngx_http_lookup_ndk_set_var_directive(u_char *name, 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); -int -ngx_http_lua_ndk_set_var_get(lua_State *L) -{ - ndk_set_var_value_pt func; - size_t len; - u_char *p; - - p = (u_char *) luaL_checklstring(L, 2, &len); - - dd("ndk.set_var metatable __index: %s", p); - - func = ngx_http_lookup_ndk_set_var_directive(p, len); - - if (func == NULL) { - return luaL_error(L, "ndk.set_var: directive \"%s\" not found " - "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, (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 */ - lua_rawget(L, 1); /* table closure */ - - return 1; -} - - -int -ngx_http_lua_ndk_set_var_set(lua_State *L) -{ - return luaL_error(L, "Not allowed"); -} - - -int -ngx_http_lua_run_set_var_directive(lua_State *L) +void +ngx_http_lua_inject_ndk_api(lua_State *L) { - ngx_int_t rc; - ndk_set_var_value_pt func; - ngx_str_t res; - ngx_http_variable_value_t arg; - u_char *p; - size_t len; - ngx_http_request_t *r; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - -#if 1 - ngx_memzero(&arg, sizeof(ngx_http_variable_value_t)); - - arg.valid = 1; -#endif - - arg.data = (u_char *) luaL_checklstring(L, 1, &len); - arg.len = len; - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - p = (u_char *) luaL_checklstring(L, lua_upvalueindex(1), &len); - - dd("calling set_var func for %s", p); - - func = (ndk_set_var_value_pt) lua_touserdata(L, lua_upvalueindex(2)); - - rc = func(r, &res, &arg); - - if (rc != NGX_OK) { - return luaL_error(L, "calling directive %s failed with code %d", - p, (int) rc); - } + lua_createtable(L, 0, 1 /* nrec */); /* ndk.* */ - lua_pushlstring(L, (char *) res.data, res.len); + lua_getglobal(L, "package"); /* ndk package */ + lua_getfield(L, -1, "loaded"); /* ndk package loaded */ + lua_pushvalue(L, -3); /* ndk package loaded ndk */ + lua_setfield(L, -2, "ndk"); /* ndk package loaded */ + lua_pop(L, 2); - return 1; + lua_setglobal(L, "ndk"); } @@ -160,32 +87,6 @@ ngx_http_lookup_ndk_set_var_directive(u_char *name, } -void -ngx_http_lua_inject_ndk_api(lua_State *L) -{ - lua_createtable(L, 0, 1 /* nrec */); /* ndk.* */ - - lua_newtable(L); /* .set_var */ - - lua_createtable(L, 0, 2 /* nrec */); /* metatable for .set_var */ - lua_pushcfunction(L, ngx_http_lua_ndk_set_var_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ngx_http_lua_ndk_set_var_set); - lua_setfield(L, -2, "__newindex"); - lua_setmetatable(L, -2); - - lua_setfield(L, -2, "set_var"); - - lua_getglobal(L, "package"); /* ndk package */ - lua_getfield(L, -1, "loaded"); /* ndk package loaded */ - lua_pushvalue(L, -3); /* ndk package loaded ndk */ - lua_setfield(L, -2, "ndk"); /* ndk package loaded */ - lua_pop(L, 2); - - lua_setglobal(L, "ndk"); -} - - int ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data, size_t var_len, ndk_set_var_value_pt *func) @@ -229,4 +130,5 @@ ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, #endif /* defined(NDK) && NDK */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/http/ngx_http_lua_pipe.c.tt2 b/src/http/ngx_http_lua_pipe.c.tt2 new file mode 100644 index 0000000..f9eab10 --- /dev/null +++ b/src/http/ngx_http_lua_pipe.c.tt2 @@ -0,0 +1,2587 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_[% subsys %]_lua_common.h" +#include "ngx_[% subsys %]_lua_input_filters.h" +#include "ngx_[% subsys %]_lua_util.h" +#include "ngx_[% subsys %]_lua_pipe.h" +#if (NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) +#include +#endif + + +#ifdef HAVE_NGX_LUA_PIPE +static ngx_rbtree_node_t *ngx_[% subsys %]_lua_pipe_lookup_pid( + ngx_rbtree_key_t key); +#if !(NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) +static void ngx_[% subsys %]_lua_pipe_sigchld_handler(int signo, + siginfo_t *siginfo, void *ucontext); +#endif +static void ngx_[% subsys %]_lua_pipe_sigchld_event_handler(ngx_event_t *ev); +static ssize_t ngx_[% subsys %]_lua_pipe_fd_read(ngx_connection_t *c, + u_char *buf, size_t size); +static ssize_t ngx_[% subsys %]_lua_pipe_fd_write(ngx_connection_t *c, + u_char *buf, size_t size); +static ngx_int_t ngx_[% subsys %]_lua_pipe_close_helper( + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced); +static ngx_int_t ngx_[% subsys %]_lua_pipe_close_stdin( + ngx_[% subsys %]_lua_pipe_t *pipe, int forced); +static ngx_int_t ngx_[% subsys %]_lua_pipe_close_stdout( + ngx_[% subsys %]_lua_pipe_t *pipe, int forced); +static ngx_int_t ngx_[% subsys %]_lua_pipe_close_stderr( + ngx_[% subsys %]_lua_pipe_t *pipe, int forced); +static void ngx_[% subsys %]_lua_pipe_proc_finalize( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, int forced); +static ngx_int_t ngx_[% subsys %]_lua_pipe_get_lua_ctx([% req_type %] *r, + ngx_[% subsys %]_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size); +static void ngx_[% subsys %]_lua_pipe_put_error( + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, u_char *errbuf, + size_t *errbuf_size); +static void ngx_[% subsys %]_lua_pipe_put_data( + ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size); +static ngx_int_t ngx_[% subsys %]_lua_pipe_add_input_buffer( + ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_[% subsys %]_lua_pipe_read_all(void *data, ssize_t bytes); +static ngx_int_t ngx_[% subsys %]_lua_pipe_read_bytes(void *data, + ssize_t bytes); +static ngx_int_t ngx_[% subsys %]_lua_pipe_read_line(void *data, + ssize_t bytes); +static ngx_int_t ngx_[% subsys %]_lua_pipe_read_any(void *data, ssize_t bytes); +static ngx_int_t ngx_[% subsys %]_lua_pipe_read( + ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx); +static ngx_int_t ngx_[% subsys %]_lua_pipe_init_ctx( + ngx_[% subsys %]_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, + u_char *errbuf, size_t *errbuf_size); +static ngx_int_t ngx_[% subsys %]_lua_pipe_write( + ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx); +static int ngx_[% subsys %]_lua_pipe_read_stdout_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_[% subsys %]_lua_pipe_read_stderr_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_[% subsys %]_lua_pipe_read_retval_helper( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr); +static int ngx_[% subsys %]_lua_pipe_write_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L); +static int ngx_[% subsys %]_lua_pipe_wait_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L); +static void ngx_[% subsys %]_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx); +static void ngx_[% subsys %]_lua_pipe_resume_read_stdout_handler( + ngx_event_t *ev); +static void ngx_[% subsys %]_lua_pipe_resume_read_stderr_handler( + ngx_event_t *ev); +static void ngx_[% subsys %]_lua_pipe_resume_write_handler(ngx_event_t *ev); +static void ngx_[% subsys %]_lua_pipe_resume_wait_handler(ngx_event_t *ev); +static ngx_int_t ngx_[% subsys %]_lua_pipe_resume([% req_type %] *r); +static void ngx_[% subsys %]_lua_pipe_dummy_event_handler(ngx_event_t *ev); +static void ngx_[% subsys %]_lua_pipe_clear_event(ngx_event_t *ev); +static void ngx_[% subsys %]_lua_pipe_proc_read_stdout_cleanup(void *data); +static void ngx_[% subsys %]_lua_pipe_proc_read_stderr_cleanup(void *data); +static void ngx_[% subsys %]_lua_pipe_proc_write_cleanup(void *data); +static void ngx_[% subsys %]_lua_pipe_proc_wait_cleanup(void *data); + + +static ngx_rbtree_t ngx_[% subsys %]_lua_pipe_rbtree; +static ngx_rbtree_node_t ngx_[% subsys %]_lua_pipe_proc_sentinel; + + +#if (NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) +static int ngx_[% subsys %]_lua_signalfd; +static struct signalfd_siginfo ngx_[% subsys %]_lua_pipe_notification; + +#define ngx_[% subsys %]_lua_read_sigfd ngx_[% subsys %]_lua_signalfd + +#else +static int ngx_[% subsys %]_lua_sigchldfd[2]; +static u_char ngx_[% subsys %]_lua_pipe_notification[1]; + +#define ngx_[% subsys %]_lua_read_sigfd ngx_[% subsys %]_lua_sigchldfd[0] +#define ngx_[% subsys %]_lua_write_sigfd ngx_[% subsys %]_lua_sigchldfd[1] +#endif + + +static ngx_connection_t *ngx_[% subsys %]_lua_sigfd_conn = NULL; + + +/* The below signals are ignored by Nginx. + * We need to reset them for the spawned child processes. */ +ngx_[% subsys %]_lua_pipe_signal_t ngx_signals[] = { + { SIGSYS, "SIGSYS" }, + { SIGPIPE, "SIGPIPE" }, + { 0, NULL } +}; + + +enum { + PIPE_ERR_CLOSED = 1, + PIPE_ERR_SYSCALL, + PIPE_ERR_NOMEM, + PIPE_ERR_TIMEOUT, + PIPE_ERR_ADD_READ_EV, + PIPE_ERR_ADD_WRITE_EV +}; + + +enum { + PIPE_READ_ALL = 0, + PIPE_READ_BYTES, + PIPE_READ_LINE, + PIPE_READ_ANY +}; + + +#define REASON_EXIT "exit" +#define REASON_SIGNAL "signal" +#define REASON_UNKNOWN "unknown" + +#define REASON_RUNNING_CODE 0 +#define REASON_EXIT_CODE 1 +#define REASON_SIGNAL_CODE 2 +#define REASON_UNKNOWN_CODE 3 + + +void +ngx_[% subsys %]_lua_pipe_init(void) +{ + ngx_rbtree_init(&ngx_[% subsys %]_lua_pipe_rbtree, + &ngx_[% subsys %]_lua_pipe_proc_sentinel, + ngx_rbtree_insert_value); +} + + +ngx_int_t +ngx_[% subsys %]_lua_pipe_add_signal_handler(ngx_cycle_t *cycle) +{ + ngx_event_t *rev; +#if (NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) + sigset_t set; + +#else + int rc; + struct sigaction sa; +#endif + +#if (NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe init signal set failed"); + return NGX_ERROR; + } + + if (sigaddset(&set, SIGCHLD) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe add SIGCHLD to signal set " + "failed"); + return NGX_ERROR; + } + + if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe block SIGCHLD failed"); + return NGX_ERROR; + } + + ngx_[% subsys %]_lua_signalfd = signalfd(-1, &set, + SFD_NONBLOCK|SFD_CLOEXEC); + if (ngx_[% subsys %]_lua_signalfd < 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe create signalfd instance " + "failed"); + return NGX_ERROR; + } + +#else /* !(NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) */ +# if (NGX_[% SUBSYS %]_LUA_HAVE_PIPE2) + rc = pipe2(ngx_[% subsys %]_lua_sigchldfd, O_NONBLOCK|O_CLOEXEC); +# else + rc = pipe(ngx_[% subsys %]_lua_sigchldfd); +# endif + + if (rc == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe init SIGCHLD fd failed"); + return NGX_ERROR; + } + +# if !(NGX_[% SUBSYS %]_LUA_HAVE_PIPE2) + if (ngx_nonblocking(ngx_[% subsys %]_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe " ngx_nonblocking_n + " SIGCHLD read fd failed"); + goto failed; + } + + if (ngx_nonblocking(ngx_[% subsys %]_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe " ngx_nonblocking_n + " SIGCHLD write fd failed"); + goto failed; + } + + /* it's ok not to set the pipe fd with O_CLOEXEC. This requires + * extra syscall */ +# endif /* !(NGX_[% SUBSYS %]_LUA_HAVE_PIPE2) */ +#endif /* NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD */ + + ngx_[% subsys %]_lua_sigfd_conn = ngx_get_connection(ngx_[% subsys %]_lua_read_sigfd, + cycle->log); + if (ngx_[% subsys %]_lua_sigfd_conn == NULL) { + goto failed; + } + + ngx_[% subsys %]_lua_sigfd_conn->log = cycle->log; + ngx_[% subsys %]_lua_sigfd_conn->recv = ngx_[% subsys %]_lua_pipe_fd_read; + rev = ngx_[% subsys %]_lua_sigfd_conn->read; + rev->log = ngx_[% subsys %]_lua_sigfd_conn->log; + rev->handler = ngx_[% subsys %]_lua_pipe_sigchld_event_handler; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + rev->skip_socket_leak_check = 1; +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + goto failed; + } + +#if !(NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_sigaction = ngx_[% subsys %]_lua_pipe_sigchld_handler; + sa.sa_flags = SA_SIGINFO; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe init signal mask failed"); + goto failed; + } + + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe sigaction(SIGCHLD) failed"); + goto failed; + } +#endif + + return NGX_OK; + +failed: + + if (ngx_[% subsys %]_lua_sigfd_conn != NULL) { + ngx_close_connection(ngx_[% subsys %]_lua_sigfd_conn); + ngx_[% subsys %]_lua_sigfd_conn = NULL; + } + + if (close(ngx_[% subsys %]_lua_read_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe close the read sigfd failed"); + } + +#if !(NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) + if (close(ngx_[% subsys %]_lua_write_sigfd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "[% log_prefix %]lua pipe close the write sigfd failed"); + } +#endif + + return NGX_ERROR; +} + + +static ngx_rbtree_node_t * +ngx_[% subsys %]_lua_pipe_lookup_pid(ngx_rbtree_key_t key) +{ + ngx_rbtree_node_t *node, *sentinel; + + node = ngx_[% subsys %]_lua_pipe_rbtree.root; + sentinel = ngx_[% subsys %]_lua_pipe_rbtree.sentinel; + + while (node != sentinel) { + if (key < node->key) { + node = node->left; + continue; + } + + if (key > node->key) { + node = node->right; + continue; + } + + return node; + } + + return NULL; +} + + +#if !(NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) +static void +ngx_[% subsys %]_lua_pipe_sigchld_handler(int signo, siginfo_t *siginfo, + void *ucontext) +{ + ngx_err_t err, saved_err; + ngx_int_t n; + + saved_err = ngx_errno; + + for ( ;; ) { + n = write(ngx_[% subsys %]_lua_write_sigfd, + ngx_[% subsys %]_lua_pipe_notification, + sizeof(ngx_[% subsys %]_lua_pipe_notification)); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "[% log_prefix %]lua pipe SIGCHLD fd write siginfo:%p", + siginfo); + + if (n >= 0) { + break; + } + + err = ngx_errno; + + if (err != NGX_EINTR) { + if (err != NGX_EAGAIN) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, err, + "[% log_prefix %]lua pipe SIGCHLD fd write " + "failed"); + } + + break; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, err, + "[% log_prefix %]lua pipe SIGCHLD fd write was " + "interrupted"); + } + + ngx_set_errno(saved_err); +} +#endif + + +static void +ngx_[% subsys %]_lua_pipe_sigchld_event_handler(ngx_event_t *ev) +{ + int n; + int status; + ngx_pid_t pid; + ngx_connection_t *c = ev->data; + ngx_rbtree_node_t *node; + ngx_[% subsys %]_lua_pipe_node_t *pipe_node; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "[% log_prefix %]lua pipe reaping children"); + + for ( ;; ) { +#if (NGX_[% SUBSYS %]_LUA_HAVE_SIGNALFD) + n = c->recv(c, (u_char *) &ngx_[% subsys %]_lua_pipe_notification, +#else + n = c->recv(c, ngx_[% subsys %]_lua_pipe_notification, +#endif + sizeof(ngx_[% subsys %]_lua_pipe_notification)); + + if (n <= 0) { + if (n == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe SIGCHLD fd read " + "failed"); + } + + break; + } + + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) { + break; + } + + if (pid < 0) { + if (ngx_errno != NGX_ECHILD) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe waitpid failed"); + } + + break; + } + + /* This log is ported from Nginx's signal handler since we override + * or block it in this implementation. */ + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "[% log_prefix %]signal %d (SIGCHLD) received " + "from %P", + SIGCHLD, pid); + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe SIGCHLD fd read pid:%P " + "status:%d", + pid, status); + + node = ngx_[% subsys %]_lua_pipe_lookup_pid(pid); + if (node != NULL) { + pipe_node = (ngx_[% subsys %]_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx != NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe resume " + "process:%p waiting for %P", + pipe_node->proc, pid); + + /* + * We need the extra parentheses around the first argument + * of ngx_post_event() just to work around macro issues in + * nginx cores older than 1.7.12 (exclusive). + */ + ngx_post_event((&pipe_node->wait_co_ctx->sleep), + &ngx_posted_events); + } + + pipe_node->proc->pipe->dead = 1; + + if (WIFSIGNALED(status)) { + pipe_node->status = WTERMSIG(status); + pipe_node->reason_code = REASON_SIGNAL_CODE; + + } else if (WIFEXITED(status)) { + pipe_node->status = WEXITSTATUS(status); + pipe_node->reason_code = REASON_EXIT_CODE; + + } else { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "[% log_prefix %]lua pipe unknown exit " + "status %d from process %P", + status, pid); + pipe_node->status = status; + pipe_node->reason_code = REASON_UNKNOWN_CODE; + } + } + } + } +} + + +static ssize_t +ngx_[% subsys %]_lua_pipe_fd_read(ngx_connection_t *c, u_char *buf, + size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = read(c->fd, buf, size); + + err = ngx_errno; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "read: fd:%d %z of %uz", + c->fd, n, size); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + return 0; + } + + if (n > 0) { + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { + rev->ready = 0; + } + + return n; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "read() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "read() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} + + +static ssize_t +ngx_[% subsys %]_lua_pipe_fd_write(ngx_connection_t *c, u_char *buf, + size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + do { + n = write(c->fd, buf, size); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "write: fd:%d %z of %uz", c->fd, n, size); + + if (n >= 0) { + if ((size_t) n != size) { + wev->ready = 0; + } + + return n; + } + + err = ngx_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "write() not ready"); + n = NGX_AGAIN; + + } else if (err != NGX_EPIPE) { + n = ngx_connection_error(c, err, "write() failed"); + break; + } + + } while (err == NGX_EINTR); + + wev->ready = 0; + + if (n == NGX_ERROR) { + wev->error = 1; + } + + return n; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_spawn(ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, + const char *file, const char **argv, int merge_stderr, size_t buffer_size, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + int in[2]; + int out[2]; + int err[2]; + int stdin_fd, stdout_fd, stderr_fd; + int errlog_fd, temp_errlog_fd; + ngx_pid_t pid; + ssize_t pool_size; + ngx_pool_t *pool; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_rbtree_node_t *node; + struct sigaction sa; + sigset_t set; + + ngx_[% subsys %]_lua_pipe_t *pp; + ngx_[% subsys %]_lua_pipe_signal_t *sig; + ngx_[% subsys %]_lua_pipe_node_t *pipe_node; + + pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2, + NGX_POOL_ALIGNMENT); + + pool = ngx_create_pool(pool_size, ngx_cycle->log); + if (pool == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + pp = ngx_pcalloc(pool, sizeof(ngx_[% subsys %]_lua_pipe_t) + + offsetof(ngx_rbtree_node_t, color) + + sizeof(ngx_[% subsys %]_lua_pipe_node_t)); + if (pp == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + goto free_pool; + } + + rc = pipe(in); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto free_pool; + } + + rc = pipe(out); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe failed: %s", + strerror(errno)) + - errbuf; + goto close_in_fd; + } + + if (!merge_stderr) { + rc = pipe(err); + if (rc == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "pipe failed: %s", strerror(errno)) + - errbuf; + goto close_in_out_fd; + } + } + + pid = fork(); + if (pid == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "fork failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + if (pid == 0) { + +#if (NGX_HAVE_CPU_AFFINITY) + /* reset the CPU affinity mask */ + ngx_uint_t log_level; + ngx_cpuset_t child_cpu_affinity; + + if (ngx_process == NGX_PROCESS_WORKER + && ngx_get_cpu_affinity(ngx_worker) != NULL) + { + CPU_ZERO(&child_cpu_affinity); + + for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { + CPU_SET(i, &child_cpu_affinity); + } + + log_level = ngx_cycle->log->log_level; + ngx_cycle->log->log_level = NGX_LOG_WARN; + ngx_setaffinity(&child_cpu_affinity, ngx_cycle->log); + ngx_cycle->log->log_level = log_level; + } +#endif + + /* reset the handler of ignored signals to the default */ + for (sig = ngx_signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + + if (sigemptyset(&sa.sa_mask) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child init signal " + "mask failed"); + exit(EXIT_FAILURE); + } + + if (sigaction(sig->signo, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child reset signal " + "handler for %s failed", + sig->signame); + exit(EXIT_FAILURE); + } + } + + /* reset signal mask */ + if (sigemptyset(&set) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child init signal set " + "failed"); + exit(EXIT_FAILURE); + } + + if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child reset signal mask " + "failed"); + exit(EXIT_FAILURE); + } + + /* close listening socket fd */ + ls = ngx_cycle->listening.elts; + for (i = 0; i < ngx_cycle->listening.nelts; i++) { + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_socket_errno, + "[% log_prefix %]lua pipe child " + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + } + + /* close and dup pipefd */ + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child failed to close the " + "in[1] pipe fd"); + } + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child failed to close the " + "out[0] pipe fd"); + } + + if (ngx_cycle->log->file && ngx_cycle->log->file->fd == STDERR_FILENO) { + errlog_fd = ngx_cycle->log->file->fd; + temp_errlog_fd = dup(errlog_fd); + + if (temp_errlog_fd == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child dup errlog fd " + "failed"); + exit(EXIT_FAILURE); + } + + if (ngx_cloexec(temp_errlog_fd) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child new errlog fd " + ngx_cloexec_n " failed"); + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe child dup old errlog " + "fd %d to new fd %d", + ngx_cycle->log->file->fd, temp_errlog_fd); + + ngx_cycle->log->file->fd = temp_errlog_fd; + } + + if (dup2(in[0], STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child dup2 stdin failed"); + exit(EXIT_FAILURE); + } + + if (dup2(out[1], STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child dup2 stdout failed"); + exit(EXIT_FAILURE); + } + + if (merge_stderr) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child dup2 stderr " + "failed"); + exit(EXIT_FAILURE); + } + + } else { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child failed to close " + "the err[0] pipe fd"); + } + + if (dup2(err[1], STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child dup2 stderr " + "failed"); + exit(EXIT_FAILURE); + } + } + + if (execvp(file, (char * const *) argv) == -1) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe child execvp() failed " + "while executing %s", + file); + } + + exit(EXIT_FAILURE); + } + + /* parent process */ + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe: failed to close the in[0] " + "pipe fd"); + } + + stdin_fd = in[1]; + + if (ngx_nonblocking(stdin_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdin_fd = stdin_fd; + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe: failed to close the out[1] " + "pipe fd"); + } + + stdout_fd = out[0]; + + if (ngx_nonblocking(stdout_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stdout_fd = stdout_fd; + + if (!merge_stderr) { + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe: failed to close the " + "err[1] pipe fd"); + } + + stderr_fd = err[0]; + + if (ngx_nonblocking(stderr_fd) == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + ngx_nonblocking_n " failed: %s", + strerror(errno)) + - errbuf; + goto close_in_out_err_fd; + } + + pp->stderr_fd = stderr_fd; + } + + node = (ngx_rbtree_node_t *) (pp + 1); + node->key = pid; + pipe_node = (ngx_[% subsys %]_lua_pipe_node_t *) &node->color; + pipe_node->proc = proc; + ngx_rbtree_insert(&ngx_[% subsys %]_lua_pipe_rbtree, node); + + pp->node = node; + pp->pool = pool; + pp->merge_stderr = merge_stderr; + pp->buffer_size = buffer_size; + + proc->_pid = pid; + proc->write_timeout = 10000; + proc->stdout_read_timeout = 10000; + proc->stderr_read_timeout = 10000; + proc->wait_timeout = 10000; + proc->pipe = pp; + + ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe spawn process:%p pid:%P " + "merge_stderr:%d buffer_size:%uz", + proc, pid, merge_stderr, buffer_size); + return NGX_OK; + +close_in_out_err_fd: + + if (!merge_stderr) { + if (close(err[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the err[0] pipe fd"); + } + + if (close(err[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the err[1] pipe fd"); + } + } + +close_in_out_fd: + + if (close(out[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the out[0] pipe fd"); + } + + if (close(out[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the out[1] pipe fd"); + } + +close_in_fd: + + if (close(in[0]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the in[0] pipe fd"); + } + + if (close(in[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the in[1] pipe fd"); + } + +free_pool: + + ngx_destroy_pool(pool); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_close_helper( + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, ngx_event_t *ev, int forced) +{ + if (ev->handler != ngx_[% subsys %]_lua_pipe_dummy_event_handler + && !forced) + { + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe cannot close fd:%d without " + "forced pipe:%p ev:%p", pipe_ctx->c->fd, pipe_ctx, ev); + return NGX_ERROR; + } + + ngx_close_connection(pipe_ctx->c); + pipe_ctx->c = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_close_stdin(ngx_[% subsys %]_lua_pipe_t *pipe, + int forced) +{ + ngx_event_t *wev; + + if (pipe->stdin_ctx == NULL) { + if (pipe->stdin_fd != -1) { + if (close(pipe->stdin_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the stdin pipe " + "fd"); + } + + pipe->stdin_fd = -1; + } + + } else if (pipe->stdin_ctx->c != NULL) { + wev = pipe->stdin_ctx->c->write; + return ngx_[% subsys %]_lua_pipe_close_helper(pipe->stdin_ctx, wev, + forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_close_stdout(ngx_[% subsys %]_lua_pipe_t *pipe, + int forced) +{ + ngx_event_t *rev; + + if (pipe->stdout_ctx == NULL) { + if (pipe->stdout_fd != -1) { + if (close(pipe->stdout_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the stdout pipe " + "fd"); + } + + pipe->stdout_fd = -1; + } + + } else if (pipe->stdout_ctx->c != NULL) { + rev = pipe->stdout_ctx->c->read; + return ngx_[% subsys %]_lua_pipe_close_helper(pipe->stdout_ctx, rev, + forced); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_close_stderr(ngx_[% subsys %]_lua_pipe_t *pipe, + int forced) +{ + ngx_event_t *rev; + + if (pipe->stderr_ctx == NULL) { + if (pipe->stderr_fd != -1) { + if (close(pipe->stderr_fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno, + "[% log_prefix %]failed to close the stderr pipe " + "fd"); + } + + pipe->stderr_fd = -1; + } + + } else if (pipe->stderr_ctx->c != NULL) { + rev = pipe->stderr_ctx->c->read; + return ngx_[% subsys %]_lua_pipe_close_helper(pipe->stderr_ctx, rev, + forced); + } + + return NGX_OK; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_shutdown_stdin( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, u_char *errbuf, + size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_[% subsys %]_lua_pipe_close_stdin(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_shutdown_stdout( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, u_char *errbuf, + size_t *errbuf_size) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rc = ngx_[% subsys %]_lua_pipe_close_stdout(pipe, 0); + if (rc != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_shutdown_stderr( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, u_char *errbuf, + size_t *errbuf_size) +{ + ngx_[% subsys %]_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr) { + /* stdout is used internally as stderr when merge_stderr is true */ + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (ngx_[% subsys %]_lua_pipe_close_stderr(pipe, 0) != NGX_OK) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_[% subsys %]_lua_pipe_proc_finalize( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, int forced) +{ + ngx_[% subsys %]_lua_pipe_t *pipe; + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe finalize process:%p pid:%P " + "forced:%d", + proc, proc->_pid, forced); + pipe = proc->pipe; + + if (pipe->node) { + ngx_rbtree_delete(&ngx_[% subsys %]_lua_pipe_rbtree, pipe->node); + pipe->node = NULL; + } + + pipe->dead = 1; + + ngx_[% subsys %]_lua_pipe_close_stdin(pipe, forced); + ngx_[% subsys %]_lua_pipe_close_stdout(pipe, forced); + + if (!pipe->merge_stderr) { + ngx_[% subsys %]_lua_pipe_close_stderr(pipe, forced); + } + + pipe->closed = 1; +} + + +void +ngx_[% subsys %]_lua_ffi_pipe_proc_destroy( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc) +{ + ngx_[% subsys %]_lua_pipe_t *pipe; + + pipe = proc->pipe; + if (pipe == NULL) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe destroy process:%p pid:%P", + proc, proc->_pid); + + if (!pipe->dead) { + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe kill process:%p pid:%P", + proc, proc->_pid); + + if (kill(proc->_pid, SIGKILL) == -1) { + if (ngx_errno != ESRCH) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe failed to kill " + "process:%p pid:%P", + proc, proc->_pid); + } + } + } + + ngx_[% subsys %]_lua_pipe_proc_finalize(proc, 1); + ngx_destroy_pool(pipe->pool); + proc->pipe = NULL; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_get_lua_ctx([% req_type %] *r, + ngx_[% subsys %]_lua_ctx_t **ctx, u_char *errbuf, size_t *errbuf_size) +{ + int rc; + + *ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + return NGX_[% SUBSYS %]_LUA_FFI_NO_REQ_CTX; + } + + rc = ngx_[% subsys %]_lua_ffi_check_context(*ctx, NGX_[% SUBSYS %]_LUA_CONTEXT_CONTENT +[% IF http_subsys %] + | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE + | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH +[% ELSIF stream_subsys %] + | NGX_STREAM_LUA_CONTEXT_PREREAD +[% END %] + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_CERT + | NGX_[% SUBSYS %]_LUA_CONTEXT_TIMER, + errbuf, errbuf_size); + if (rc != NGX_OK) { + return NGX_[% SUBSYS %]_LUA_FFI_BAD_CONTEXT; + } + + return NGX_OK; +} + + +static void +ngx_[% subsys %]_lua_pipe_put_error(ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, + u_char *errbuf, size_t *errbuf_size) +{ + switch (pipe_ctx->err_type) { + + case PIPE_ERR_CLOSED: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + break; + + case PIPE_ERR_SYSCALL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(pipe_ctx->pipe_errno)) + - errbuf; + break; + + case PIPE_ERR_NOMEM: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + break; + + case PIPE_ERR_TIMEOUT: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "timeout") + - errbuf; + break; + + case PIPE_ERR_ADD_READ_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add read event") + - errbuf; + break; + + case PIPE_ERR_ADD_WRITE_EV: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, + "failed to add write event") + - errbuf; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "unexpected err type: %d", pipe_ctx->err_type); + ngx_[% subsys %]_lua_assert(NULL); + } +} + + +static void +ngx_[% subsys %]_lua_pipe_put_data(ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx, u_char **buf, size_t *buf_size) +{ + size_t size = 0; + size_t chunk_size; + size_t nbufs; + u_char *p; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_chain_t **ll; + + nbufs = 0; + ll = NULL; + + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + + if (cl->next) { + ll = &cl->next; + } + + size += chunk_size; + + nbufs++; + } + + if (*buf_size < size) { + *buf = NULL; + *buf_size = size; + + return; + } + + *buf_size = size; + + p = *buf; + for (cl = pipe_ctx->bufs_in; cl; cl = cl->next) { + b = cl->buf; + chunk_size = b->last - b->pos; + p = ngx_cpymem(p, b->pos, chunk_size); + } + + if (nbufs > 1 && ll) { + *ll = pipe->free_bufs; + pipe->free_bufs = pipe_ctx->bufs_in; + pipe_ctx->bufs_in = pipe_ctx->buf_in; + } + + if (pipe_ctx->buffer.pos == pipe_ctx->buffer.last) { + pipe_ctx->buffer.pos = pipe_ctx->buffer.start; + pipe_ctx->buffer.last = pipe_ctx->buffer.start; + } + + if (pipe_ctx->bufs_in) { + pipe_ctx->buf_in->buf->last = pipe_ctx->buffer.pos; + pipe_ctx->buf_in->buf->pos = pipe_ctx->buffer.pos; + } +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_add_input_buffer(ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx) +{ + ngx_chain_t *cl; + + cl = ngx_[% subsys %]_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + return NGX_ERROR; + } + + pipe_ctx->buf_in->next = cl; + pipe_ctx->buf_in = cl; + pipe_ctx->buffer = *cl->buf; + + return NGX_OK; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_read_all(void *data, ssize_t bytes) +{ + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read all"); + + return ngx_[% subsys %]_lua_read_all(&pipe_ctx->buffer, pipe_ctx->buf_in, + bytes, ngx_cycle->log); +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_read_bytes(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read bytes %z", + bytes); + + rc = ngx_[% subsys %]_lua_read_bytes(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, + ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_read_line(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read line"); + + rc = ngx_[% subsys %]_lua_read_line(&pipe_ctx->buffer, pipe_ctx->buf_in, + bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_read_any(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx = data; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read any"); + + rc = ngx_[% subsys %]_lua_read_any(&pipe_ctx->buffer, pipe_ctx->buf_in, + &pipe_ctx->rest, bytes, ngx_cycle->log); + if (rc == NGX_ERROR) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_read(ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx) +{ + int rc; + int read; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_event_t *rev; + ngx_connection_t *c; + + c = pipe_ctx->c; + rev = c->read; + b = &pipe_ctx->buffer; + read = 0; + + for ( ;; ) { + size = b->last - b->pos; + + if (size || pipe_ctx->eof) { + rc = pipe_ctx->input_filter(pipe_ctx->input_filter_ctx, size); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read done pipe:%p", + pipe_ctx); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + continue; + } + + if (read && !rev->ready) { + break; + } + + size = b->end - b->last; + + if (size == 0) { + rc = ngx_[% subsys %]_lua_pipe_add_input_buffer(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + b = &pipe_ctx->buffer; + size = (size_t) (b->end - b->last); + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe try to read data %uz pipe:%p", + size, pipe_ctx); + + n = c->recv(c, b->last, size); + read = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read data returned %z pipe:%p", + n, pipe_ctx); + + if (n == NGX_AGAIN) { + break; + } + + if (n == 0) { + pipe_ctx->eof = 1; + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe closed pipe:%p", + pipe_ctx); + continue; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe read data error pipe:%p", + pipe_ctx); + + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + return NGX_ERROR; + } + + b->last += n; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_init_ctx( + ngx_[% subsys %]_lua_pipe_ctx_t **pipe_ctx_pt, int fd, ngx_pool_t *pool, + u_char *errbuf, size_t *errbuf_size) +{ + ngx_connection_t *c; + + if (fd == -1) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + *pipe_ctx_pt = ngx_pcalloc(pool, sizeof(ngx_[% subsys %]_lua_pipe_ctx_t)); + if (*pipe_ctx_pt == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory") + - errbuf; + return NGX_ERROR; + } + + c = ngx_get_connection(fd, ngx_cycle->log); + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no connection") + - errbuf; + return NGX_ERROR; + } + + c->log = ngx_cycle->log; + c->recv = ngx_[% subsys %]_lua_pipe_fd_read; + c->read->handler = ngx_[% subsys %]_lua_pipe_dummy_event_handler; + c->read->log = c->log; + +#ifdef HAVE_SOCKET_CLOEXEC_PATCH + c->read->skip_socket_leak_check = 1; +#endif + + c->send = ngx_[% subsys %]_lua_pipe_fd_write; + c->write->handler = ngx_[% subsys %]_lua_pipe_dummy_event_handler; + c->write->log = c->log; + (*pipe_ctx_pt)->c = c; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe init pipe ctx:%p fd:*%d", + *pipe_ctx_pt, fd); + + return NGX_OK; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_read([% req_type %] *r, + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, int from_stderr, + int reader_type, size_t length, u_char **buf, size_t *buf_size, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_[% subsys %]_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe read process:%p pid:%P", + proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->merge_stderr && from_stderr) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "merged to stdout") + - errbuf; + return NGX_ERROR; + } + + if (from_stderr) { + if (pipe->stderr_ctx == NULL) { + if (ngx_[% subsys %]_lua_pipe_init_ctx(&pipe->stderr_ctx, + pipe->stderr_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stderr_ctx->err_type = 0; + } + + pipe_ctx = pipe->stderr_ctx; + + } else { + if (pipe->stdout_ctx == NULL) { + if (ngx_[% subsys %]_lua_pipe_init_ctx(&pipe->stdout_ctx, + pipe->stdout_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdout_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdout_ctx; + } + + c = pipe_ctx->c; + if (c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + rev = c->read; + if (rev->handler != ngx_[% subsys %]_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy reading") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->input_filter_ctx = pipe_ctx; + + switch (reader_type) { + + case PIPE_READ_ALL: + pipe_ctx->input_filter = ngx_[% subsys %]_lua_pipe_read_all; + break; + + case PIPE_READ_BYTES: + pipe_ctx->input_filter = ngx_[% subsys %]_lua_pipe_read_bytes; + break; + + case PIPE_READ_LINE: + pipe_ctx->input_filter = ngx_[% subsys %]_lua_pipe_read_line; + break; + + case PIPE_READ_ANY: + pipe_ctx->input_filter = ngx_[% subsys %]_lua_pipe_read_any; + break; + + default: + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "[% log_prefix %]unexpected reader_type: %d", + reader_type); + ngx_[% subsys %]_lua_assert(NULL); + } + + pipe_ctx->rest = length; + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->bufs_in = + ngx_[% subsys %]_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, + pipe->buffer_size); + + if (pipe_ctx->bufs_in == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = pipe_ctx->bufs_in; + pipe_ctx->buffer = *pipe_ctx->buf_in->buf; + } + + rc = ngx_[% subsys %]_lua_pipe_read(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + ngx_[% subsys %]_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + + c->data = wait_co_ctx; + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_READ_EV; + goto error; + } + + wait_co_ctx->data = proc; + + if (from_stderr) { + rev->handler = ngx_[% subsys %]_lua_pipe_resume_read_stderr_handler; + wait_co_ctx->cleanup = ngx_[% subsys %]_lua_pipe_proc_read_stderr_cleanup; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_[% subsys %]_lua_pipe_resume_read_stdout_handler; + wait_co_ctx->cleanup = ngx_[% subsys %]_lua_pipe_proc_read_stdout_cleanup; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe add timer for reading: %d(ms) " + "process:%p pid:%P pipe:%p ev:%p", + timeout, proc, proc->_pid, pipe, rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe read yielding process:%p pid:%P " + "pipe:%p", + proc, proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + if (pipe_ctx->bufs_in) { + ngx_[% subsys %]_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +/* + * ngx_[% subsys %]_lua_ffi_pipe_get_read_result should only be called just + * after ngx_[% subsys %]_lua_ffi_pipe_proc_read, so we omit most of the sanity + * check already done in ngx_[% subsys %]_lua_ffi_pipe_proc_read. + */ +int +ngx_[% subsys %]_lua_ffi_pipe_get_read_result([% req_type %] *r, + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, + size_t *buf_size, u_char *errbuf, size_t *errbuf_size) +{ + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe get read result process:%p pid:%P", + proc, proc->_pid); + + pipe = proc->pipe; + pipe_ctx = from_stderr ? pipe->stderr_ctx : pipe->stdout_ctx; + + if (!pipe_ctx->err_type) { + ngx_[% subsys %]_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + return NGX_OK; + } + + if (pipe_ctx->bufs_in) { + ngx_[% subsys %]_lua_pipe_put_data(pipe, pipe_ctx, buf, buf_size); + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_DECLINED; + } + + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_write(ngx_[% subsys %]_lua_pipe_t *pipe, + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx) +{ + size_t size; + ngx_int_t n; + ngx_buf_t *b; + ngx_connection_t *c; + + c = pipe_ctx->c; + b = pipe_ctx->buf_in->buf; + + for ( ;; ) { + size = b->last - b->pos; + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe try to write data %uz pipe:%p", + size, pipe_ctx); + + n = c->send(c, b->pos, size); + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe write returned %i pipe:%p", + n, pipe_ctx); + + if (n >= 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + + if (!pipe->free_bufs) { + pipe->free_bufs = pipe_ctx->buf_in; + + } else { + pipe->free_bufs->next = pipe_ctx->buf_in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe write done pipe:%p", + pipe_ctx); + return NGX_OK; + } + + continue; + } + + /* NGX_ERROR || NGX_AGAIN */ + break; + } + + if (n == NGX_ERROR) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, ngx_errno, + "[% log_prefix %]lua pipe write data error pipe:%p", + pipe_ctx); + + if (ngx_errno == NGX_EPIPE) { + pipe_ctx->err_type = PIPE_ERR_CLOSED; + + } else { + pipe_ctx->err_type = PIPE_ERR_SYSCALL; + pipe_ctx->pipe_errno = ngx_errno; + } + + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +ssize_t +ngx_[% subsys %]_lua_ffi_pipe_proc_write([% req_type %] *r, + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_buf_t *b; + ngx_msec_t timeout; + ngx_chain_t *cl; + ngx_event_t *wev; + + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + rc = ngx_[% subsys %]_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe write process:%p pid:%P", + proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + if (pipe->stdin_ctx == NULL) { + if (ngx_[% subsys %]_lua_pipe_init_ctx(&pipe->stdin_ctx, pipe->stdin_fd, + pipe->pool, errbuf, + errbuf_size) + != NGX_OK) + { + return NGX_ERROR; + } + + } else { + pipe->stdin_ctx->err_type = 0; + } + + pipe_ctx = pipe->stdin_ctx; + if (pipe_ctx->c == NULL) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "closed") - errbuf; + return NGX_ERROR; + } + + wev = pipe_ctx->c->write; + if (wev->handler != ngx_[% subsys %]_lua_pipe_dummy_event_handler) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy writing") + - errbuf; + return NGX_ERROR; + } + + pipe_ctx->rest = len; + + cl = ngx_[% subsys %]_lua_chain_get_free_buf(ngx_cycle->log, pipe->pool, + &pipe->free_bufs, len); + if (cl == NULL) { + pipe_ctx->err_type = PIPE_ERR_NOMEM; + goto error; + } + + pipe_ctx->buf_in = cl; + b = pipe_ctx->buf_in->buf; + b->last = ngx_copy(b->last, data, len); + + rc = ngx_[% subsys %]_lua_pipe_write(pipe, pipe_ctx); + if (rc == NGX_ERROR) { + goto error; + } + + if (rc == NGX_OK) { + return len; + } + + /* rc == NGX_AGAIN */ + wait_co_ctx = ctx->cur_co_ctx; + pipe_ctx->c->data = wait_co_ctx; + + wev->handler = ngx_[% subsys %]_lua_pipe_resume_write_handler; + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + pipe_ctx->err_type = PIPE_ERR_ADD_WRITE_EV; + goto error; + } + + wait_co_ctx->data = proc; + wait_co_ctx->cleanup = ngx_[% subsys %]_lua_pipe_proc_write_cleanup; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe add timer for writing: " + "%d(ms) process:%p pid:%P pipe:%p ev:%p", + timeout, proc, proc->_pid, pipe, wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe write yielding process:%p pid:%P " + "pipe:%p", + proc, proc->_pid, pipe); + + return NGX_AGAIN; + +error: + + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; +} + + +/* + * ngx_[% subsys %]_lua_ffi_pipe_get_write_result should only be called just + * after ngx_[% subsys %]_lua_ffi_pipe_proc_write, so we omit most of the + * sanity check already done in ngx_[% subsys %]_lua_ffi_pipe_proc_write. + */ +ssize_t +ngx_[% subsys %]_lua_ffi_pipe_get_write_result([% req_type %] *r, + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, u_char *errbuf, + size_t *errbuf_size) +{ + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe get write result process:%p " + "pid:%P", + proc, proc->_pid); + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe_ctx->err_type) { + ngx_[% subsys %]_lua_pipe_put_error(pipe_ctx, errbuf, errbuf_size); + return NGX_ERROR; + } + + return pipe_ctx->rest; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_wait([% req_type %] *r, + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, char **reason, int *status, + u_char *errbuf, size_t *errbuf_size) +{ + int rc; + ngx_rbtree_node_t *node; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_node_t *pipe_node; + + rc = ngx_[% subsys %]_lua_pipe_get_lua_ctx(r, &ctx, errbuf, errbuf_size); + if (rc != NGX_OK) { + return rc; + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe wait process:%p pid:%P", + proc, proc->_pid); + + pipe = proc->pipe; + if (pipe == NULL || pipe->closed) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + node = pipe->node; + pipe_node = (ngx_[% subsys %]_lua_pipe_node_t *) &node->color; + if (pipe_node->wait_co_ctx) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "pipe busy waiting") + - errbuf; + return NGX_ERROR; + } + + if (pipe_node->reason_code == REASON_RUNNING_CODE) { + wait_co_ctx = ctx->cur_co_ctx; + wait_co_ctx->data = proc; + ngx_memzero(&wait_co_ctx->sleep, sizeof(ngx_event_t)); + wait_co_ctx->sleep.handler = ngx_[% subsys %]_lua_pipe_resume_wait_handler; + wait_co_ctx->sleep.data = wait_co_ctx; + wait_co_ctx->sleep.log = r->connection->log; + wait_co_ctx->cleanup = ngx_[% subsys %]_lua_pipe_proc_wait_cleanup; + + pipe_node->wait_co_ctx = wait_co_ctx; + + if (proc->wait_timeout > 0) { + ngx_add_timer(&wait_co_ctx->sleep, proc->wait_timeout); + ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe add timer for waiting: " + "%d(ms) process:%p pid:%P ev:%p", + proc->wait_timeout, proc, proc->_pid, + &wait_co_ctx->sleep); + } + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua pipe wait yielding process:%p " + "pid:%P", + proc, proc->_pid); + + return NGX_AGAIN; + } + + *status = pipe_node->status; + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + *reason = REASON_EXIT; + break; + + case REASON_SIGNAL_CODE: + *reason = REASON_SIGNAL; + break; + + default: + *reason = REASON_UNKNOWN; + } + + ngx_[% subsys %]_lua_pipe_proc_finalize(proc, 0); + + if (*status == 0) { + return NGX_OK; + } + + return NGX_DECLINED; +} + + +int +ngx_[% subsys %]_lua_ffi_pipe_proc_kill( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, int signal, u_char *errbuf, + size_t *errbuf_size) +{ + ngx_pid_t pid; + ngx_[% subsys %]_lua_pipe_t *pipe; + + pipe = proc->pipe; + + if (pipe == NULL || pipe->dead) { + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") - errbuf; + return NGX_ERROR; + } + + pid = proc->_pid; + + if (kill(pid, signal) == -1) { + switch (ngx_errno) { + case EINVAL: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "invalid signal") + - errbuf; + break; + + case ESRCH: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "exited") + - errbuf; + break; + + default: + *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "%s", + strerror(ngx_errno)) + - errbuf; + } + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static int +ngx_[% subsys %]_lua_pipe_read_stdout_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + return ngx_[% subsys %]_lua_pipe_read_retval_helper(proc, L, 0); +} + + +static int +ngx_[% subsys %]_lua_pipe_read_stderr_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + return ngx_[% subsys %]_lua_pipe_read_retval_helper(proc, L, 1); +} + + +static int +ngx_[% subsys %]_lua_pipe_read_retval_helper( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L, int from_stderr) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *rev; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + if (from_stderr) { + pipe_ctx = pipe->stderr_ctx; + + } else { + pipe_ctx = pipe->stdout_ctx; + } + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_[% subsys %]_lua_pipe_read(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + rev = pipe_ctx->c->read; + + if (from_stderr) { + rev->handler = ngx_[% subsys %]_lua_pipe_resume_read_stderr_handler; + timeout = proc->stderr_read_timeout; + + } else { + rev->handler = ngx_[% subsys %]_lua_pipe_resume_read_stdout_handler; + timeout = proc->stdout_read_timeout; + } + + if (timeout > 0) { + ngx_add_timer(rev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe add timer for reading: " + "%d(ms) proc:%p pid:%P pipe:%p ev:%p", + timeout, proc, proc->_pid, pipe, rev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe read yielding process:%p pid:%P " + "pipe:%p", + proc, proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_[% subsys %]_lua_pipe_write_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + int rc; + ngx_msec_t timeout; + ngx_event_t *wev; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_pipe_ctx_t *pipe_ctx; + + pipe = proc->pipe; + pipe_ctx = pipe->stdin_ctx; + + if (pipe->timeout) { + pipe->timeout = 0; + pipe_ctx->err_type = PIPE_ERR_TIMEOUT; + return 0; + } + + rc = ngx_[% subsys %]_lua_pipe_write(pipe, pipe_ctx); + if (rc != NGX_AGAIN) { + return 0; + } + + wev = pipe_ctx->c->write; + wev->handler = ngx_[% subsys %]_lua_pipe_resume_write_handler; + timeout = proc->write_timeout; + + if (timeout > 0) { + ngx_add_timer(wev, timeout); + ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe add timer for writing: " + "%d(ms) proc:%p pid:%P pipe:%p ev:%p", + timeout, proc, proc->_pid, pipe, wev); + } + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe write yielding process:%p pid:%P " + "pipe:%p", + proc, proc->_pid, pipe); + + return NGX_AGAIN; +} + + +static int +ngx_[% subsys %]_lua_pipe_wait_retval( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L) +{ + int nret; + ngx_rbtree_node_t *node; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_pipe_node_t *pipe_node; + + pipe = proc->pipe; + node = pipe->node; + pipe_node = (ngx_[% subsys %]_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + if (pipe->timeout) { + pipe->timeout = 0; + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; + } + + ngx_[% subsys %]_lua_pipe_proc_finalize(pipe_node->proc, 0); + + if (pipe_node->status == 0) { + lua_pushboolean(L, 1); + lua_pushliteral(L, REASON_EXIT); + lua_pushinteger(L, pipe_node->status); + nret = 3; + + } else { + lua_pushboolean(L, 0); + + switch (pipe_node->reason_code) { + + case REASON_EXIT_CODE: + lua_pushliteral(L, REASON_EXIT); + break; + + case REASON_SIGNAL_CODE: + lua_pushliteral(L, REASON_SIGNAL); + break; + + default: + lua_pushliteral(L, REASON_UNKNOWN); + } + + lua_pushinteger(L, pipe_node->status); + nret = 3; + } + + return nret; +} + + +static void +ngx_[% subsys %]_lua_pipe_resume_helper(ngx_event_t *ev, + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx) +{ +[% IF http_subsys %] + ngx_connection_t *c; +[% END %] + + [% req_type %] *r; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + if (ev->timedout) { + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->timeout = 1; + ev->timedout = 0; + } + + ngx_http_lua_pipe_clear_event(ev); + + r = ngx_[% subsys %]_lua_get_req(wait_co_ctx->co); +[% IF http_subsys %] + c = r->connection; +[% END %] + + ctx = ngx_[% subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + ngx_[% subsys %]_lua_assert(ctx != NULL); + + ctx->cur_co_ctx = wait_co_ctx; + + if (ctx->entered_content_phase) { + (void) ngx_[% subsys %]_lua_pipe_resume(r); + + } else { + ctx->resume_handler = ngx_[% subsys %]_lua_pipe_resume; + ngx_[% req_subsys %]_core_run_phases(r); + } + +[% IF http_subsys %] + ngx_http_run_posted_requests(c); +[% END %] +} + + +static void +ngx_[% subsys %]_lua_pipe_resume_read_stdout_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_[% subsys %]_lua_pipe_read_stdout_retval; + ngx_[% subsys %]_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_[% subsys %]_lua_pipe_resume_read_stderr_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_[% subsys %]_lua_pipe_read_stderr_retval; + ngx_[% subsys %]_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_[% subsys %]_lua_pipe_resume_write_handler(ngx_event_t *ev) +{ + ngx_connection_t *c = ev->data; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + wait_co_ctx = c->data; + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_[% subsys %]_lua_pipe_write_retval; + ngx_[% subsys %]_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static void +ngx_[% subsys %]_lua_pipe_resume_wait_handler(ngx_event_t *ev) +{ + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx = ev->data; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + proc = wait_co_ctx->data; + pipe = proc->pipe; + pipe->retval_handler = ngx_[% subsys %]_lua_pipe_wait_retval; + ngx_[% subsys %]_lua_pipe_resume_helper(ev, wait_co_ctx); +} + + +static ngx_int_t +ngx_[% subsys %]_lua_pipe_resume([% req_type %] *r) +{ + int nret; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_pipe_t *pipe; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->resume_handler = ngx_[% subsys %]_lua_wev_handler; + ctx->cur_co_ctx->cleanup = NULL; + + proc = ctx->cur_co_ctx->data; + pipe = proc->pipe; + nret = pipe->retval_handler(proc, ctx->cur_co_ctx->co); + if (nret == NGX_AGAIN) { + return NGX_DONE; + } + + c = r->connection; + vm = ngx_[% subsys %]_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_[% subsys %]_lua_run_thread(vm, r, ctx, nret); + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_[% subsys %]_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_[% subsys %]_lua_finalize_request(r, NGX_DONE); + return ngx_[% subsys %]_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_[% subsys %]_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_[% subsys %]_lua_pipe_dummy_event_handler(ngx_event_t *ev) +{ + /* do nothing */ +} + + +static void +ngx_[% subsys %]_lua_pipe_clear_event(ngx_event_t *ev) +{ + ev->handler = ngx_[% subsys %]_lua_pipe_dummy_event_handler; + + if (ev->timer_set) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ev->log, 0, + "[% log_prefix %]lua pipe del timer for ev:%p", + ev); + ngx_del_timer(ev); + } + + if (ev->posted) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ev->log, 0, + "[% log_prefix %]lua pipe del posted event for ev:%p", + ev); + ngx_delete_posted_event(ev); + } +} + + +static void +ngx_[% subsys %]_lua_pipe_proc_read_stdout_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx = data; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe proc read stdout cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdout_ctx->c; + if (c) { + rev = c->read; + ngx_[% subsys %]_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_[% subsys %]_lua_pipe_proc_read_stderr_cleanup(void *data) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx = data; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe proc read stderr cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stderr_ctx->c; + if (c) { + rev = c->read; + ngx_[% subsys %]_lua_pipe_clear_event(rev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_[% subsys %]_lua_pipe_proc_write_cleanup(void *data) +{ + ngx_event_t *wev; + ngx_connection_t *c; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx = data; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe proc write cleanup"); + + proc = wait_co_ctx->data; + c = proc->pipe->stdin_ctx->c; + if (c) { + wev = c->write; + ngx_[% subsys %]_lua_pipe_clear_event(wev); + } + + wait_co_ctx->cleanup = NULL; +} + + +static void +ngx_[% subsys %]_lua_pipe_proc_wait_cleanup(void *data) +{ + ngx_rbtree_node_t *node; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx = data; + ngx_[% subsys %]_lua_pipe_node_t *pipe_node; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua pipe proc wait cleanup"); + + proc = wait_co_ctx->data; + node = proc->pipe->node; + pipe_node = (ngx_[% subsys %]_lua_pipe_node_t *) &node->color; + pipe_node->wait_co_ctx = NULL; + + ngx_[% subsys %]_lua_pipe_clear_event(&wait_co_ctx->sleep); + + wait_co_ctx->cleanup = NULL; +} + + +#endif /* HAVE_NGX_LUA_PIPE */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/http/ngx_http_lua_pipe.h.tt2 b/src/http/ngx_http_lua_pipe.h.tt2 new file mode 100644 index 0000000..eb8bb19 --- /dev/null +++ b/src/http/ngx_http_lua_pipe.h.tt2 @@ -0,0 +1,95 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_[% SUBSYS %]_LUA_PIPE_H_INCLUDED_ +#define _NGX_[% SUBSYS %]_LUA_PIPE_H_INCLUDED_ + + +#include "ngx_[% subsys %]_lua_common.h" + + +typedef ngx_int_t (*ngx_[% subsys %]_lua_pipe_input_filter)( + void *data, ssize_t bytes); + + +typedef struct { + ngx_connection_t *c; + ngx_[% subsys %]_lua_pipe_input_filter input_filter; + void *input_filter_ctx; + size_t rest; + ngx_chain_t *buf_in; + ngx_chain_t *bufs_in; + ngx_buf_t buffer; + ngx_err_t pipe_errno; + unsigned err_type:16; + unsigned eof:1; +} ngx_[% subsys %]_lua_pipe_ctx_t; + + +typedef struct ngx_[% subsys %]_lua_pipe_s ngx_[% subsys %]_lua_pipe_t; + + +typedef struct { + ngx_pid_t _pid; + ngx_msec_t write_timeout; + ngx_msec_t stdout_read_timeout; + ngx_msec_t stderr_read_timeout; + ngx_msec_t wait_timeout; + /* pipe hides the implementation from the Lua binding */ + ngx_[% subsys %]_lua_pipe_t *pipe; +} ngx_[% subsys %]_lua_ffi_pipe_proc_t; + + +typedef int (*ngx_[% subsys %]_lua_pipe_retval_handler)( + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc, lua_State *L); + + +struct ngx_[% subsys %]_lua_pipe_s { + ngx_pool_t *pool; + ngx_chain_t *free_bufs; + ngx_rbtree_node_t *node; + int stdin_fd; + int stdout_fd; + int stderr_fd; + ngx_[% subsys %]_lua_pipe_ctx_t *stdin_ctx; + ngx_[% subsys %]_lua_pipe_ctx_t *stdout_ctx; + ngx_[% subsys %]_lua_pipe_ctx_t *stderr_ctx; + ngx_[% subsys %]_lua_pipe_retval_handler retval_handler; + size_t buffer_size; + unsigned closed:1; + unsigned dead:1; + unsigned timeout:1; + unsigned merge_stderr:1; +}; + + +typedef struct { + u_char color; + u_char reason_code; + int status; + ngx_[% subsys %]_lua_co_ctx_t *wait_co_ctx; + ngx_[% subsys %]_lua_ffi_pipe_proc_t *proc; +} ngx_[% subsys %]_lua_pipe_node_t; + + +typedef struct { + int signo; + char *signame; +} ngx_[% subsys %]_lua_pipe_signal_t; + + +#if !(NGX_WIN32) && defined(HAVE_SOCKET_CLOEXEC_PATCH) +#define HAVE_NGX_LUA_PIPE 1 + + +void ngx_[% subsys %]_lua_pipe_init(void); +ngx_int_t ngx_[% subsys %]_lua_pipe_add_signal_handler(ngx_cycle_t *cycle); +#endif + + +#endif /* _NGX_[% SUBSYS %]_LUA_PIPE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/http/ngx_http_lua_req_body.c b/src/http/ngx_http_lua_req_body.c index e6bf3c1..5fe4564 100644 --- a/src/http/ngx_http_lua_req_body.c +++ b/src/http/ngx_http_lua_req_body.c @@ -114,11 +114,6 @@ 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_HTTP_SPECIAL_RESPONSE) { ctx->exit_code = rc; ctx->exited = 1; @@ -130,11 +125,8 @@ ngx_http_lua_ngx_req_read_body(lua_State *L) return lua_yield(L, 0); } -#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) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/http/ngx_http_lua_req_method.c b/src/http/ngx_http_lua_req_method.c index a4969b9..a41e5af 100644 --- a/src/http/ngx_http_lua_req_method.c +++ b/src/http/ngx_http_lua_req_method.c @@ -10,142 +10,9 @@ #include "ddebug.h" -#include "ngx_http_lua_req_method.h" #include "ngx_http_lua_subrequest.h" -#include "ngx_http_lua_util.h" -static int ngx_http_lua_ngx_req_get_method(lua_State *L); -static int ngx_http_lua_ngx_req_set_method(lua_State *L); - - -void -ngx_http_lua_inject_req_method_api(lua_State *L) -{ - lua_pushcfunction(L, ngx_http_lua_ngx_req_get_method); - lua_setfield(L, -2, "get_method"); - - lua_pushcfunction(L, ngx_http_lua_ngx_req_set_method); - lua_setfield(L, -2, "set_method"); -} - - -static int -ngx_http_lua_ngx_req_get_method(lua_State *L) -{ - int n; - ngx_http_request_t *r; - - n = lua_gettop(L); - if (n != 0) { - return luaL_error(L, "only one argument expected but got %d", n); - } - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - 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; -} - - -static int -ngx_http_lua_ngx_req_set_method(lua_State *L) -{ - int n; - int method; - ngx_http_request_t *r; - - n = lua_gettop(L); - if (n != 1) { - return luaL_error(L, "only one argument expected but got %d", n); - } - - method = luaL_checkint(L, 1); - - r = ngx_http_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "request object not found"); - } - - ngx_http_lua_check_fake_request(L, r); - - 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 luaL_error(L, "unsupported HTTP method: %d", method); - } - - r->method = method; - - return 0; -} - - -#ifndef NGX_LUA_NO_FFI_API int ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r) { @@ -247,7 +114,6 @@ ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method) r->method = method; return NGX_OK; } -#endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/http/ngx_http_lua_req_method.h b/src/http/ngx_http_lua_req_method.h deleted file mode 100644 index f8aa1af..0000000 --- a/src/http/ngx_http_lua_req_method.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * 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" - - -void ngx_http_lua_inject_req_method_api(lua_State *L); - - -#endif /* _NGX_HTTP_LUA_METHOD_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/http/ngx_http_lua_rewriteby.c b/src/http/ngx_http_lua_rewriteby.c index 08f7566..84df6d2 100644 --- a/src/http/ngx_http_lua_rewriteby.c +++ b/src/http/ngx_http_lua_rewriteby.c @@ -62,7 +62,7 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r) #endif if (cur_ph < last_ph) { - dd("swaping the contents of cur_ph and last_ph..."); + dd("swapping the contents of cur_ph and last_ph..."); tmp = *cur_ph; @@ -149,11 +149,6 @@ 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/src/http/ngx_http_lua_setby.c b/src/http/ngx_http_lua_setby.c index d4288b5..f00468c 100644 --- a/src/http/ngx_http_lua_setby.c +++ b/src/http/ngx_http_lua_setby.c @@ -15,10 +15,7 @@ #include "ngx_http_lua_exception.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_pcrefix.h" -#include "ngx_http_lua_time.h" #include "ngx_http_lua_log.h" -#include "ngx_http_lua_regex.h" -#include "ngx_http_lua_variable.h" #include "ngx_http_lua_string.h" #include "ngx_http_lua_misc.h" #include "ngx_http_lua_consts.h" diff --git a/src/http/ngx_http_lua_ssl_ocsp.c b/src/http/ngx_http_lua_ssl_ocsp.c index 9ec8b50..d1805b2 100644 --- a/src/http/ngx_http_lua_ssl_ocsp.c +++ b/src/http/ngx_http_lua_ssl_ocsp.c @@ -16,8 +16,6 @@ #include "ngx_http_lua_common.h" -#ifndef NGX_LUA_NO_FFI_API - #ifdef NGX_HTTP_LUA_USE_OCSP static int ngx_http_lua_ssl_empty_status_callback(ngx_ssl_conn_t *ssl_conn, void *data); @@ -500,7 +498,5 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, #endif /* NGX_HTTP_LUA_USE_OCSP */ } -#endif /* NGX_LUA_NO_FFI_API */ - #endif /* NGX_HTTP_SSL */ diff --git a/src/http/ngx_http_lua_ssl_session_fetchby.c b/src/http/ngx_http_lua_ssl_session_fetchby.c index 1dbc326..4092129 100644 --- a/src/http/ngx_http_lua_ssl_session_fetchby.c +++ b/src/http/ngx_http_lua_ssl_session_fetchby.c @@ -262,26 +262,11 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -#if defined(nginx_version) && nginx_version >= 1003014 - -# if nginx_version >= 1009000 - +#if defined(nginx_version) && nginx_version >= 1009000 ngx_set_connection_log(fc, clcf->error_log); -# else - - ngx_http_set_connection_log(fc, clcf->error_log); - -# endif - #else - - fc->log->file = clcf->error_log->file; - - if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - fc->log->log_level = clcf->error_log->log_level; - } - + ngx_http_set_connection_log(fc, clcf->error_log); #endif if (cctx == NULL) { @@ -557,8 +542,6 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) } -#ifndef NGX_LUA_NO_FFI_API - /* de-serialized a SSL session and set it back to the request at lua context */ int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, @@ -569,6 +552,7 @@ ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, ngx_ssl_conn_t *ssl_conn; ngx_connection_t *c; ngx_ssl_session_t *session = NULL; + ngx_ssl_session_t *old_session; ngx_http_lua_ssl_ctx_t *cctx; c = r->connection; @@ -599,12 +583,15 @@ ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, return NGX_ERROR; } + old_session = cctx->session; cctx->session = session; + if (old_session != NULL) { + ngx_ssl_free_session(old_session); + } + return NGX_OK; } -#endif /* NGX_LUA_NO_FFI_API */ - #endif /* NGX_HTTP_SSL */ diff --git a/src/http/ngx_http_lua_ssl_session_storeby.c b/src/http/ngx_http_lua_ssl_session_storeby.c index a02f729..f867ee2 100644 --- a/src/http/ngx_http_lua_ssl_session_storeby.c +++ b/src/http/ngx_http_lua_ssl_session_storeby.c @@ -224,25 +224,11 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); -#if defined(nginx_version) && nginx_version >= 1003014 - -# if nginx_version >= 1009000 - +#if defined(nginx_version) && nginx_version >= 1009000 ngx_set_connection_log(fc, clcf->error_log); -# else - - ngx_http_set_connection_log(fc, clcf->error_log); - -# endif - #else - - fc->log->file = clcf->error_log->file; - - if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - fc->log->log_level = clcf->error_log->log_level; - } + ngx_http_set_connection_log(fc, clcf->error_log); #endif @@ -428,8 +414,6 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) } -#ifndef NGX_LUA_NO_FFI_API - /* serialize a session from lua context into buf. * the memory allocation of buf should be handled externally. */ int @@ -615,7 +599,5 @@ ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, return 2 * cctx->session_id.len; } -#endif /* NGX_LUA_NO_FFI_API */ - #endif /* NGX_HTTP_SSL */ diff --git a/src/http/ngx_http_lua_subrequest.c b/src/http/ngx_http_lua_subrequest.c index 826a43c..761eea7 100644 --- a/src/http/ngx_http_lua_subrequest.c +++ b/src/http/ngx_http_lua_subrequest.c @@ -1031,6 +1031,14 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) dd("pr_coctx status: %d", (int) pr_coctx->sr_statuses[ctx->index]); /* copy subrequest response headers */ + if (ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r, ctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to set default content type: %i", rc); + return NGX_ERROR; + } + } pr_coctx->sr_headers[ctx->index] = &r->headers_out; @@ -1073,11 +1081,7 @@ ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, ngx_int_t rc) if (ctx->body) { -#if defined(nginx_version) && nginx_version >= 1001004 ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif &pr_ctx->free_bufs, &pr_ctx->busy_bufs, &ctx->body, (ngx_buf_tag_t) &ngx_http_lua_module); @@ -1449,7 +1453,7 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; -#if nginx_version >= 1009005 +#if defined(nginx_version) && nginx_version >= 1009005 if (r->subrequests == 0) { #if defined(NGX_DTRACE) && NGX_DTRACE @@ -1568,7 +1572,7 @@ ngx_http_lua_subrequest(ngx_http_request_t *r, sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; -#if nginx_version >= 1009005 +#if defined(nginx_version) && nginx_version >= 1009005 sr->subrequests = r->subrequests - 1; #endif diff --git a/src/subsys/api/ngx_subsys_lua_api.h.tt2 b/src/subsys/api/ngx_subsys_lua_api.h.tt2 index c9e37b9..081e5c2 100644 --- a/src/subsys/api/ngx_subsys_lua_api.h.tt2 +++ b/src/subsys/api/ngx_subsys_lua_api.h.tt2 @@ -43,6 +43,13 @@ typedef struct { } ngx_[% subsys %]_lua_value_t; +typedef struct { + int len; + /* this padding hole on 64-bit systems is expected */ + u_char *data; +} ngx_[% subsys %]_lua_ffi_str_t; + + lua_State *ngx_[% subsys %]_lua_get_global_state(ngx_conf_t *cf); [% req_type %] *ngx_[% subsys %]_lua_get_request(lua_State *L); @@ -53,7 +60,8 @@ ngx_int_t ngx_[% subsys %]_lua_add_package_preload(ngx_conf_t *cf, ngx_int_t ngx_[% subsys %]_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, u_char *key_data, size_t key_len, ngx_[% subsys %]_lua_value_t *value); -ngx_shm_zone_t *ngx_[% subsys %]_lua_find_zone(u_char *name_data, size_t name_len); +ngx_shm_zone_t *ngx_[% subsys %]_lua_find_zone(u_char *name_data, + size_t name_len); ngx_shm_zone_t *ngx_[% subsys %]_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag); diff --git a/src/subsys/ngx_subsys_lua_api.c.tt2 b/src/subsys/ngx_subsys_lua_api.c.tt2 index d594d75..d12d98f 100644 --- a/src/subsys/ngx_subsys_lua_api.c.tt2 +++ b/src/subsys/ngx_subsys_lua_api.c.tt2 @@ -85,8 +85,8 @@ ngx_[% subsys %]_lua_add_package_preload(ngx_conf_t *cf, const char *package, ngx_shm_zone_t * -ngx_[% subsys %]_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, - void *tag) +ngx_[% subsys %]_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, + size_t size, void *tag) { ngx_[% subsys %]_lua_main_conf_t *lmcf; ngx_[% subsys %]_lua_shm_zone_ctx_t *ctx; diff --git a/src/subsys/ngx_subsys_lua_args.c.tt2 b/src/subsys/ngx_subsys_lua_args.c.tt2 index d91988e..adc78db 100644 --- a/src/subsys/ngx_subsys_lua_args.c.tt2 +++ b/src/subsys/ngx_subsys_lua_args.c.tt2 @@ -17,7 +17,6 @@ [% IF http_subsys %] static int ngx_[% subsys %]_lua_ngx_req_set_uri_args(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_req_get_uri_args(lua_State *L); static int ngx_[% subsys %]_lua_ngx_req_get_post_args(lua_State *L); @@ -81,64 +80,6 @@ ngx_[% subsys %]_lua_ngx_req_set_uri_args(lua_State *L) } -static int -ngx_[% subsys %]_lua_ngx_req_get_uri_args(lua_State *L) -{ - [% req_type %] *r; - u_char *buf; - u_char *last; - int retval; - int n; - int max; - - 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) { - max = luaL_checkinteger(L, 1); - lua_pop(L, 1); - - } else { - max = NGX_[% SUBSYS %]_LUA_MAX_ARGS; - } - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - ngx_[% subsys %]_lua_check_fake_request(L, r); - - if (r->args.len == 0) { - lua_createtable(L, 0, 0); - return 1; - } - - /* we copy r->args over to buf to simplify - * unescaping query arg keys and values */ - - buf = ngx_palloc(r->pool, r->args.len); - if (buf == NULL) { - return luaL_error(L, "no memory"); - } - - lua_createtable(L, 0, 4); - - ngx_memcpy(buf, r->args.data, r->args.len); - - last = buf + r->args.len; - - retval = ngx_[% subsys %]_lua_parse_args(L, buf, last, max); - - ngx_pfree(r->pool, buf); - - return retval; -} - - static int ngx_[% subsys %]_lua_ngx_req_get_post_args(lua_State *L) { @@ -313,10 +254,12 @@ ngx_[% subsys %]_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max } if (max > 0 && ++count == max) { - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, - "lua hit query args limit %d", max); + lua_pushliteral(L, "truncated"); - return 1; + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua hit query args limit %d", + max); + return 2; } } else { @@ -370,18 +313,11 @@ ngx_[% subsys %]_lua_inject_req_args_api(lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_req_set_uri_args); lua_setfield(L, -2, "set_uri_args"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_req_get_uri_args); - lua_setfield(L, -2, "get_uri_args"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_req_get_uri_args); - lua_setfield(L, -2, "get_query_args"); /* deprecated */ - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_req_get_post_args); lua_setfield(L, -2, "get_post_args"); } -#ifndef NGX_LUA_NO_FFI_API size_t ngx_[% subsys %]_lua_ffi_req_get_querystring_len([% req_type %] *r) { @@ -390,7 +326,8 @@ ngx_[% subsys %]_lua_ffi_req_get_querystring_len([% req_type %] *r) int -ngx_[% subsys %]_lua_ffi_req_get_uri_args_count([% req_type %] *r, int max) +ngx_[% subsys %]_lua_ffi_req_get_uri_args_count([% req_type %] *r, int max, + int *truncated) { int count; u_char *p, *last; @@ -399,6 +336,8 @@ ngx_[% subsys %]_lua_ffi_req_get_uri_args_count([% req_type %] *r, int max) return NGX_[% SUBSYS %]_LUA_FFI_BAD_CONTEXT; } + *truncated = 0; + if (max < 0) { max = NGX_[% SUBSYS %]_LUA_MAX_ARGS; } @@ -420,8 +359,9 @@ ngx_[% subsys %]_lua_ffi_req_get_uri_args_count([% req_type %] *r, int max) if (count) { if (max > 0 && count > max) { count = max; + *truncated = 1; ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua hit query args limit %d", max); + "[% log_prefix %]lua hit query args limit %d", max); } return count; @@ -547,7 +487,6 @@ ngx_[% subsys %]_lua_ffi_req_get_uri_args([% req_type %] *r, u_char *buf, return i; } -#endif /* NGX_LUA_NO_FFI_API */ [% END # http %] diff --git a/src/subsys/ngx_subsys_lua_balancer.c.tt2 b/src/subsys/ngx_subsys_lua_balancer.c.tt2 index af7fbef..b84cc61 100644 --- a/src/subsys/ngx_subsys_lua_balancer.c.tt2 +++ b/src/subsys/ngx_subsys_lua_balancer.c.tt2 @@ -548,12 +548,6 @@ ngx_[% subsys %]_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data #endif -[% IF http_subsys %] -[%#- if not under http, always build those APIs as a workaround for no lua-resty-core support in subsystems other than http %] - -#ifndef NGX_LUA_NO_FFI_API -[% END %] - int ngx_[% subsys %]_lua_ffi_balancer_set_current_peer([% req_type %] *r, const u_char *addr, size_t addr_len, int port, char **err) @@ -798,12 +792,12 @@ ngx_[% subsys %]_lua_ffi_balancer_set_more_tries([% req_type %] *r, int count, char **err) { [% IF http_subsys %] -#if (nginx_version >= 1007005) +#if defined(nginx_version) && nginx_version >= 1007005 [% ELSIF stream_subsys %] #if (HAS_NGX_STREAM_PROXY_GET_NEXT_UPSTREAM_TRIES_PATCH) [% END %] - ngx_uint_t max_tries, total; + ngx_uint_t max_tries, total; #endif ngx_[% subsys %]_lua_ctx_t *ctx; ngx_[% subsys %]_upstream_t *u; @@ -848,7 +842,7 @@ ngx_[% subsys %]_lua_ffi_balancer_set_more_tries([% req_type %] *r, } [% IF http_subsys %] -#if (nginx_version >= 1007005) +#if defined(nginx_version) && nginx_version >= 1007005 max_tries = u->conf->next_upstream_tries; total = bp->total_tries + u->peer.tries - 1; @@ -951,6 +945,5 @@ ngx_[% subsys %]_lua_ffi_balancer_get_last_failure([% req_type %] *r, return bp->last_peer_state; } -[% IF http_subsys %] -#endif /* NGX_LUA_NO_FFI_API */ -[% END %] + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_cache.c.tt2 b/src/subsys/ngx_subsys_lua_cache.c.tt2 index ad9a52b..710e870 100644 --- a/src/subsys/ngx_subsys_lua_cache.c.tt2 +++ b/src/subsys/ngx_subsys_lua_cache.c.tt2 @@ -156,7 +156,8 @@ ngx_[% subsys %]_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L, n = lua_gettop(L); - dd("XXX cache key: [% "[%" %]s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_[% subsys %]_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { @@ -240,7 +241,8 @@ ngx_[% subsys %]_lua_cache_loadfile(ngx_log_t *log, lua_State *L, dd("CACHE file key already pre-calculated"); } - dd("XXX cache key for file: [% "[%" %]s]", cache_key); + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, + "looking up Lua code cache with key '%s'", cache_key); rc = ngx_[% subsys %]_lua_cache_load_code(log, L, (char *) cache_key); if (rc == NGX_OK) { diff --git a/src/subsys/ngx_subsys_lua_common.h.tt2 b/src/subsys/ngx_subsys_lua_common.h.tt2 index a5b2242..244ba61 100644 --- a/src/subsys/ngx_subsys_lua_common.h.tt2 +++ b/src/subsys/ngx_subsys_lua_common.h.tt2 @@ -9,13 +9,6 @@ #define _NGX_[% SUBSYS %]_LUA_COMMON_H_INCLUDED_ -[% IF stream_subsys %] -#ifndef NGX_LUA_NO_FFI_API -#define NGX_LUA_NO_FFI_API -#endif -[% END %] - - #include #include #include @@ -48,10 +41,10 @@ [% IF http_subsys %] -#if !defined(nginx_version) || (nginx_version < 1006000) +#if !defined(nginx_version) || nginx_version < 1006000 #error at least nginx 1.6.0 is required but found an older version [% ELSIF stream_subsys %] -#if !defined(nginx_version) || (nginx_version < 1013006) +#if !defined(nginx_version) || nginx_version < 1013006 #error at least nginx 1.13.6 is required but found an older version [% END %] #endif @@ -69,6 +62,11 @@ #endif +#if !defined(LUAJIT_VERSION_NUM) || (LUAJIT_VERSION_NUM < 20000) +# error unsupported LuaJIT version +#endif + + #if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) # define NGX_[% SUBSYS %]_LUA_USE_OCSP 1 #endif @@ -78,11 +76,11 @@ #ifndef NGX_HTTP_PERMANENT_REDIRECT # define NGX_HTTP_PERMANENT_REDIRECT 308 #endif +[% END %] -[% END %] #ifndef NGX_HAVE_SHA1 -# if (nginx_version >= 1011002) +# if defined(nginx_version) && nginx_version >= 1011002 # define NGX_HAVE_SHA1 1 # endif #endif @@ -175,10 +173,8 @@ typedef struct { [% END %] -#ifndef NGX_LUA_NO_FFI_API #define NGX_[% SUBSYS %]_LUA_FFI_NO_REQ_CTX -100 #define NGX_[% SUBSYS %]_LUA_FFI_BAD_CONTEXT -101 -#endif #if (NGX_PTR_SIZE >= 8 && !defined(_WIN64)) @@ -228,8 +224,6 @@ struct ngx_[% subsys %]_lua_main_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; - ngx_flag_t load_resty_core; - ngx_int_t max_pending_timers; ngx_int_t pending_timers; @@ -308,11 +302,13 @@ struct ngx_[% subsys %]_lua_main_conf_s { ngx_uint_t malloc_trim_req_count; [% IF http_subsys %] -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 /* the following 2 fields are only used by ngx.req.raw_headers() for now */ ngx_buf_t **busy_buf_ptrs; ngx_int_t busy_buf_ptr_count; #endif + + ngx_int_t host_var_index; [% END %] ngx_flag_t set_sa_restart; @@ -595,6 +591,13 @@ struct ngx_[% subsys %]_lua_co_ctx_s { the ngx.thread.spawn() call */ unsigned sem_resume_status:1; + + unsigned is_wrap:1; /* set when creating coroutines via + coroutine.wrap */ + + unsigned propagate_error:1; /* set when propagating an error + from a coroutine to its + parent */ }; @@ -706,6 +709,10 @@ typedef struct ngx_[% subsys %]_lua_ctx_s { unsigned headers_set:1; /* whether the user has set custom response headers */ +[% IF http_subsys %] + unsigned mime_set:1; /* whether the user has set Content-Type + response header */ +[% END %] [% IF http_subsys %] unsigned entered_rewrite_phase:1; diff --git a/src/subsys/ngx_subsys_lua_consts.c.tt2 b/src/subsys/ngx_subsys_lua_consts.c.tt2 index 6149d41..def6abe 100644 --- a/src/subsys/ngx_subsys_lua_consts.c.tt2 +++ b/src/subsys/ngx_subsys_lua_consts.c.tt2 @@ -120,10 +120,8 @@ ngx_http_lua_inject_http_consts(lua_State *L) lua_pushinteger(L, NGX_HTTP_MOVED_TEMPORARILY); lua_setfield(L, -2, "HTTP_MOVED_TEMPORARILY"); -#if defined(nginx_version) && nginx_version >= 8042 lua_pushinteger(L, NGX_HTTP_SEE_OTHER); lua_setfield(L, -2, "HTTP_SEE_OTHER"); -#endif lua_pushinteger(L, NGX_HTTP_PERMANENT_REDIRECT); lua_setfield(L, -2, "HTTP_PERMANENT_REDIRECT"); diff --git a/src/subsys/ngx_subsys_lua_contentby.c.tt2 b/src/subsys/ngx_subsys_lua_contentby.c.tt2 index 4148da6..78c3abc 100644 --- a/src/subsys/ngx_subsys_lua_contentby.c.tt2 +++ b/src/subsys/ngx_subsys_lua_contentby.c.tt2 @@ -235,10 +235,6 @@ 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/subsys/ngx_subsys_lua_control.c.tt2 b/src/subsys/ngx_subsys_lua_control.c.tt2 index 0397a44..285a06a 100644 --- a/src/subsys/ngx_subsys_lua_control.c.tt2 +++ b/src/subsys/ngx_subsys_lua_control.c.tt2 @@ -22,7 +22,6 @@ static int ngx_http_lua_ngx_redirect(lua_State *L); [% END %] -static int ngx_[% subsys %]_lua_ngx_exit(lua_State *L); static int ngx_[% subsys %]_lua_on_abort(lua_State *L); @@ -39,16 +38,8 @@ ngx_[% subsys %]_lua_inject_control_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_exec); lua_setfield(L, -2, "exec"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_exit); - lua_setfield(L, -2, "throw_error"); /* deprecated */ [% END %] - /* ngx.exit */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_exit); - lua_setfield(L, -2, "exit"); - /* ngx.on_abort */ lua_pushcfunction(L, ngx_[% subsys %]_lua_on_abort); @@ -296,128 +287,6 @@ ngx_[% subsys %]_lua_ngx_redirect(lua_State *L) [% END # http %] -static int -ngx_[% subsys %]_lua_ngx_exit(lua_State *L) -{ - ngx_int_t rc; - [% req_type %] *r; - ngx_[% subsys %]_lua_ctx_t *ctx; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); - if (ctx == NULL) { - return luaL_error(L, "no request ctx found"); - } - - ngx_[% subsys %]_lua_check_context(L, ctx, NGX_[% SUBSYS %]_LUA_CONTEXT_CONTENT - | NGX_[% SUBSYS %]_LUA_CONTEXT_TIMER - | NGX_[% SUBSYS %]_LUA_CONTEXT_BALANCER - | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_CERT -[% IF http_subsys %] - | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE - | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS - | NGX_[% SUBSYS %]_LUA_CONTEXT_HEADER_FILTER - | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE - | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH -[% ELSIF stream_subsys %] - | NGX_STREAM_LUA_CONTEXT_PREREAD -[% END %] - ); - - rc = (ngx_int_t) luaL_checkinteger(L, 1); - -[% IF http_subsys %] - if (ctx->context & (NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_CERT - | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE - | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH)) -[% ELSIF stream_subsys %] - if (ctx->context & NGX_STREAM_LUA_CONTEXT_SSL_CERT) -[% END # http %] - { - -#if (NGX_[% SUBSYS %]_SSL) - - ctx->exit_code = rc; - ctx->exited = 1; - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua exit with code %i", rc); - -[% IF http_subsys %] - if (ctx->context == NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE) { - return 0; - } -[% END %] - - return lua_yield(L, 0); - -#else - - return luaL_error(L, "no SSL support"); - -#endif - } - -[% IF http_subsys %] - if (ctx->no_abort - && rc != NGX_ERROR - && rc != NGX_HTTP_CLOSE - && rc != NGX_HTTP_REQUEST_TIME_OUT - && rc != NGX_HTTP_CLIENT_CLOSED_REQUEST) - { - return luaL_error(L, "attempt to abort with pending subrequests"); - } - - if ((r->header_sent || ctx->header_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) { - 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; - } -[% END # http %] - - dd("setting exit code: %d", (int) rc); - - ctx->exit_code = rc; - ctx->exited = 1; - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua exit with code %i", ctx->exit_code); - -[% IF http_subsys %] - if (ctx->context & (NGX_HTTP_LUA_CONTEXT_HEADER_FILTER - | NGX_HTTP_LUA_CONTEXT_BALANCER)) - { - return 0; - } - -[% ELSIF stream_subsys %] - if (ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) { - return 0; - } -[% END %] - - dd("calling yield"); - return lua_yield(L, 0); -} - - static int ngx_[% subsys %]_lua_on_abort(lua_State *L) { @@ -476,7 +345,6 @@ ngx_[% subsys %]_lua_on_abort(lua_State *L) } -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_exit([% req_type %] *r, int status, u_char *err, size_t *errlen) @@ -489,24 +357,34 @@ ngx_[% subsys %]_lua_ffi_exit([% req_type %] *r, int status, u_char *err, return NGX_ERROR; } - if (ngx_[% subsys %]_lua_ffi_check_context(ctx, NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE - | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS - | NGX_[% SUBSYS %]_LUA_CONTEXT_CONTENT + + if (ngx_[% subsys %]_lua_ffi_check_context(ctx, NGX_[% SUBSYS %]_LUA_CONTEXT_CONTENT | NGX_[% SUBSYS %]_LUA_CONTEXT_TIMER - | NGX_[% SUBSYS %]_LUA_CONTEXT_HEADER_FILTER | NGX_[% SUBSYS %]_LUA_CONTEXT_BALANCER | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_CERT +[% IF http_subsys %] + NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE + | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_HEADER_FILTER | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH, +[% ELSIF stream_subsys %] + | NGX_STREAM_LUA_CONTEXT_PREREAD, +[% END %] err, errlen) != NGX_OK) { return NGX_ERROR; } +[% IF http_subsys %] if (ctx->context & (NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_CERT | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH)) + +[% ELSIF stream_subsys %] + if (ctx->context & NGX_STREAM_LUA_CONTEXT_SSL_CERT) +[% END # http %] { #if (NGX_[% SUBSYS %]_SSL) @@ -517,9 +395,11 @@ ngx_[% subsys %]_lua_ffi_exit([% req_type %] *r, int status, u_char *err, ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, "lua exit with code %d", status); +[% IF http_subsys %] if (ctx->context == NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE) { return NGX_DONE; } +[% END %] return NGX_OK; @@ -566,14 +446,21 @@ ngx_[% subsys %]_lua_ffi_exit([% req_type %] *r, int status, u_char *err, ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, "lua exit with code %i", ctx->exit_code); - if (ctx->context & (NGX_[% SUBSYS %]_LUA_CONTEXT_HEADER_FILTER - | NGX_[% SUBSYS %]_LUA_CONTEXT_BALANCER)) +[% IF http_subsys %] + if (ctx->context & (NGX_HTTP_LUA_CONTEXT_HEADER_FILTER + | NGX_HTTP_LUA_CONTEXT_BALANCER)) { return NGX_DONE; } +[% ELSIF stream_subsys %] + if (ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) { + return NGX_DONE; + } +[% END %] + return NGX_OK; } -#endif /* NGX_LUA_NO_FFI_API */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_coroutine.c.tt2 b/src/subsys/ngx_subsys_lua_coroutine.c.tt2 index a4b097c..1168035 100644 --- a/src/subsys/ngx_subsys_lua_coroutine.c.tt2 +++ b/src/subsys/ngx_subsys_lua_coroutine.c.tt2 @@ -25,6 +25,7 @@ static int ngx_[% subsys %]_lua_coroutine_create(lua_State *L); +static int ngx_[% subsys %]_lua_coroutine_wrap(lua_State *L); static int ngx_[% subsys %]_lua_coroutine_resume(lua_State *L); static int ngx_[% subsys %]_lua_coroutine_yield(lua_State *L); static int ngx_[% subsys %]_lua_coroutine_status(lua_State *L); @@ -62,6 +63,45 @@ ngx_[% subsys %]_lua_coroutine_create(lua_State *L) } +static int +ngx_[% subsys %]_lua_coroutine_wrap_runner(lua_State *L) +{ + /* retrieve closure and insert it at the bottom of + * the stack for coroutine.resume() */ + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + + return ngx_[% subsys %]_lua_coroutine_resume(L); +} + + +static int +ngx_[% subsys %]_lua_coroutine_wrap(lua_State *L) +{ + [% req_type %] *r; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_co_ctx_t *coctx = NULL; + + r = ngx_[% subsys %]_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no request ctx found"); + } + + ngx_[% subsys %]_lua_coroutine_create_helper(L, r, ctx, &coctx); + + coctx->is_wrap = 1; + + lua_pushcclosure(L, ngx_[% subsys %]_lua_coroutine_wrap_runner, 1); + + return 1; +} + + int ngx_[% subsys %]_lua_coroutine_create_helper(lua_State *L, [% req_type %] *r, ngx_[% subsys %]_lua_ctx_t *ctx, @@ -270,7 +310,7 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) int rc; /* new coroutine table */ - lua_createtable(L, 0 /* narr */, 14 /* nrec */); + lua_createtable(L, 0 /* narr */, 16 /* nrec */); /* get old coroutine table */ lua_getglobal(L, "coroutine"); @@ -282,6 +322,9 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) lua_getfield(L, -1, "create"); lua_setfield(L, -3, "_create"); + lua_getfield(L, -1, "wrap"); + lua_setfield(L, -3, "_wrap"); + lua_getfield(L, -1, "resume"); lua_setfield(L, -3, "_resume"); @@ -297,6 +340,9 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_coroutine_create); lua_setfield(L, -2, "__create"); + lua_pushcfunction(L, ngx_[% subsys %]_lua_coroutine_wrap); + lua_setfield(L, -2, "__wrap"); + lua_pushcfunction(L, ngx_[% subsys %]_lua_coroutine_resume); lua_setfield(L, -2, "__resume"); @@ -311,7 +357,7 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) /* inject coroutine APIs */ { const char buf[] = - "local keys = {'create', 'yield', 'resume', 'status'}\n" + "local keys = {'create', 'yield', 'resume', 'status', 'wrap'}\n" #ifdef OPENRESTY_LUAJIT "local get_req = require 'thread.exdata'\n" #else @@ -341,24 +387,18 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) "return std(...)\n" "end\n" "end\n" - "local create, resume = coroutine.create, coroutine.resume\n" - "coroutine.wrap = function(f)\n" - "local co = create(f)\n" - "return function(...) return select(2, resume(co, ...)) end\n" - "end\n" - "package.loaded.coroutine = coroutine"; - + "package.loaded.coroutine = coroutine" #if 0 "debug.sethook(function () collectgarbage() end, 'rl', 1)" #endif ; - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=coroutine.wrap"); + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=coroutine_api"); } if (rc != 0) { ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to load Lua code for coroutine.wrap(): %i: %s", + "failed to load Lua code for coroutine_api: %i: %s", rc, lua_tostring(L, -1)); lua_pop(L, 1); @@ -368,7 +408,7 @@ ngx_[% subsys %]_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L) rc = lua_pcall(L, 0, 0, 0); if (rc != 0) { ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to run the Lua code for coroutine.wrap(): %i: %s", + "failed to run the Lua code for coroutine_api: %i: %s", rc, lua_tostring(L, -1)); lua_pop(L, 1); } diff --git a/src/subsys/ngx_subsys_lua_ctx.c.tt2 b/src/subsys/ngx_subsys_lua_ctx.c.tt2 index e247416..7258ad2 100644 --- a/src/subsys/ngx_subsys_lua_ctx.c.tt2 +++ b/src/subsys/ngx_subsys_lua_ctx.c.tt2 @@ -25,71 +25,6 @@ static ngx_int_t ngx_[% subsys %]_lua_ngx_ctx_add_cleanup([% req_type %] *r, static void ngx_[% subsys %]_lua_ngx_ctx_cleanup(void *data); -int -ngx_[% subsys %]_lua_ngx_get_ctx(lua_State *L) -{ - [% req_type %] *r; - ngx_[% subsys %]_lua_ctx_t *ctx; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - - ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); - if (ctx == NULL) { - return luaL_error(L, "no request ctx found"); - } - - if (ctx->ctx_ref == LUA_NOREF) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua create ngx.ctx table for the current request"); - - lua_pushliteral(L, ngx_[% subsys %]_lua_ctx_tables_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_createtable(L, 0 /* narr */, 4 /* nrec */); - lua_pushvalue(L, -1); - ctx->ctx_ref = luaL_ref(L, -3); - - if (ngx_[% subsys %]_lua_ngx_ctx_add_cleanup(r, ctx->ctx_ref) != NGX_OK) { - return luaL_error(L, "no memory"); - } - - return 1; - } - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua fetching existing ngx.ctx table for the current " - "request"); - - lua_pushliteral(L, ngx_[% subsys %]_lua_ctx_tables_key); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_rawgeti(L, -1, ctx->ctx_ref); - - return 1; -} - - -int -ngx_[% subsys %]_lua_ngx_set_ctx(lua_State *L) -{ - [% req_type %] *r; - ngx_[% subsys %]_lua_ctx_t *ctx; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - - ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); - if (ctx == NULL) { - return luaL_error(L, "no request ctx found"); - } - - return ngx_[% subsys %]_lua_ngx_set_ctx_helper(L, r, ctx, 3); -} - - int ngx_[% subsys %]_lua_ngx_set_ctx_helper(lua_State *L, [% req_type %] *r, ngx_[% subsys %]_lua_ctx_t *ctx, int index) @@ -130,7 +65,6 @@ ngx_[% subsys %]_lua_ngx_set_ctx_helper(lua_State *L, [% req_type %] *r, } -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_get_ctx_ref([% req_type %] *r) { @@ -163,7 +97,6 @@ ngx_[% subsys %]_lua_ffi_set_ctx_ref([% req_type %] *r, int ref) return NGX_OK; } -#endif /* NGX_LUA_NO_FFI_API */ static ngx_int_t diff --git a/src/subsys/ngx_subsys_lua_ctx.h.tt2 b/src/subsys/ngx_subsys_lua_ctx.h.tt2 index 115ff1e..c3dd4dc 100644 --- a/src/subsys/ngx_subsys_lua_ctx.h.tt2 +++ b/src/subsys/ngx_subsys_lua_ctx.h.tt2 @@ -12,8 +12,6 @@ #include "ngx_[% subsys %]_lua_common.h" -int ngx_[% subsys %]_lua_ngx_get_ctx(lua_State *L); -int ngx_[% subsys %]_lua_ngx_set_ctx(lua_State *L); int ngx_[% subsys %]_lua_ngx_set_ctx_helper(lua_State *L, [% req_type %] *r, ngx_[% subsys %]_lua_ctx_t *ctx, int index); diff --git a/src/subsys/ngx_subsys_lua_directive.c.tt2 b/src/subsys/ngx_subsys_lua_directive.c.tt2 index 27e0dd9..c5e1b94 100644 --- a/src/subsys/ngx_subsys_lua_directive.c.tt2 +++ b/src/subsys/ngx_subsys_lua_directive.c.tt2 @@ -190,6 +190,23 @@ ngx_[% subsys %]_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_[% subsys %]_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "lua_load_resty_core is deprecated (the lua-resty-core " + "library is required since " +[% IF http_subsys %] + "ngx_lua v0.10.16)"); +[% ELSIF stream_subsys %] + "ngx_stream_lua v0.0.8)"); +[% END %] + + return NGX_CONF_OK; +} + + char * ngx_[% subsys %]_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -478,10 +495,6 @@ ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) dd("enter"); -#if defined(nginx_version) && nginx_version >= 8042 && nginx_version <= 8053 - return "does not work with " NGINX_VER; -#endif - /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; @@ -1472,11 +1485,12 @@ ngx_[% subsys %]_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag, size_t tag_ found: - ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", - tag_len, tag, cf->conf_file->file.name.data - + cf->conf_file->file.name.len - p, - p, cf->conf_file->line); - *chunkname_len = len; + p = ngx_snprintf(out, len, "=%*s(%*s:%d)%Z", + tag_len, tag, cf->conf_file->file.name.data + + cf->conf_file->file.name.len - p, + p, cf->conf_file->line); + + *chunkname_len = p - out - 1; /* exclude the trailing '\0' byte */ return out; } @@ -1659,12 +1673,12 @@ ngx_[% subsys %]_lua_conf_read_lua_token(ngx_conf_t *cf, ngx_uint_t start_line; ngx_str_t *word; ngx_buf_t *b; -#if nginx_version >= 1009002 +#if defined(nginx_version) && nginx_version >= 1009002 ngx_buf_t *dump; #endif b = cf->conf_file->buffer; -#if nginx_version >= 1009002 +#if defined(nginx_version) && nginx_version >= 1009002 dump = cf->conf_file->dump; #endif start = b->pos; @@ -1735,7 +1749,7 @@ ngx_[% subsys %]_lua_conf_read_lua_token(ngx_conf_t *cf, b->last = b->start + len + n; start = b->start; -#if nginx_version >= 1009002 +#if defined(nginx_version) && nginx_version >= 1009002 if (dump) { dump->last = ngx_cpymem(dump->last, b->start + len, size); } diff --git a/src/subsys/ngx_subsys_lua_directive.h.tt2 b/src/subsys/ngx_subsys_lua_directive.h.tt2 index eec72af..ba21ce4 100644 --- a/src/subsys/ngx_subsys_lua_directive.h.tt2 +++ b/src/subsys/ngx_subsys_lua_directive.h.tt2 @@ -55,6 +55,8 @@ char *ngx_[% subsys %]_lua_init_worker_by_lua_block(ngx_conf_t *cf, char *ngx_[% subsys %]_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_[% subsys %]_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_[% subsys %]_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); [% IF http_subsys %] #if defined(NDK) && NDK diff --git a/src/subsys/ngx_subsys_lua_initworkerby.c.tt2 b/src/subsys/ngx_subsys_lua_initworkerby.c.tt2 index 271a3ab..c58b755 100644 --- a/src/subsys/ngx_subsys_lua_initworkerby.c.tt2 +++ b/src/subsys/ngx_subsys_lua_initworkerby.c.tt2 @@ -15,6 +15,9 @@ [% IF stream_subsys %] #include "ngx_stream_lua_contentby.h" + +[% ELSIF http_subsys %] +#include "ngx_[% subsys %]_lua_pipe.h" [% END %] @@ -47,6 +50,7 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) [% END %] [% IF http_subsys %] + ngx_conf_file_t cf_file; ngx_http_core_loc_conf_t *clcf, *top_clcf; ngx_http_lua_loc_conf_t *top_llcf; @@ -70,6 +74,8 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) # endif ) { + /* disable init_worker_by_lua* and destroy lua VM in cache processes */ + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, "lua close the global Lua VM %p in the " "cache helper process %P", lmcf->lua, ngx_pid); @@ -79,9 +85,18 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } + +[% IF http_subsys %] +#ifdef HAVE_NGX_LUA_PIPE + if (ngx_[% subsys %]_lua_pipe_add_signal_handler(cycle) != NGX_OK) { + return NGX_ERROR; + } +#endif +[% END %] + #endif /* NGX_WIN32 */ -#if NGX_[% SUBSYS %]_LUA_HAVE_SA_RESTART +#if (NGX_[% SUBSYS %]_LUA_HAVE_SA_RESTART) if (lmcf->set_sa_restart) { ngx_[% subsys %]_lua_set_sa_restart(ngx_cycle->log); } @@ -93,7 +108,6 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) conf_ctx = (ngx_[% subsys %]_conf_ctx_t *) cycle->conf_ctx[ngx_[% subsys %]_module.index]; - [% subsys %]_ctx.main_conf = conf_ctx->main_conf; [% IF http_subsys %] top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; @@ -128,12 +142,8 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) ngx_memcpy(fake_cycle, cycle, sizeof(ngx_cycle_t)); -#if defined(nginx_version) && nginx_version >= 9007 - ngx_queue_init(&fake_cycle->reusable_connections_queue); -#endif - if (ngx_array_init(&fake_cycle->listening, cycle->pool, cycle->listening.nelts || 1, sizeof(ngx_listening_t)) @@ -142,8 +152,6 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) goto failed; } -#if defined(nginx_version) && nginx_version >= 1003007 - if (ngx_array_init(&fake_cycle->paths, cycle->pool, cycle->paths.nelts || 1, sizeof(ngx_path_t *)) != NGX_OK) @@ -151,8 +159,6 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) goto failed; } -#endif - part = &cycle->open_files.part; ofile = part->elts; @@ -208,6 +214,10 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) conf.log = cycle->log; [% IF http_subsys %] + ngx_memzero(&cf_file, sizeof(cf_file)); + cf_file.file.name = cycle->conf_file; + conf.conf_file = &cf_file; + http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { @@ -221,6 +231,12 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) return NGX_ERROR; } + [% subsys %]_ctx.main_conf = ngx_pcalloc(conf.pool, + sizeof(void *) * ngx_[% subsys %]_max_module); + if ([% subsys %]_ctx.main_conf == NULL) { + return NGX_ERROR; + } + #if defined(nginx_version) && nginx_version >= 1009011 modules = cycle->modules; #else @@ -234,6 +250,21 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) module = modules[i]->ctx; + if (module->create_main_conf) { + cur = module->create_main_conf(&conf); + if (cur == NULL) { + return NGX_ERROR; + } + + if (ngx_modules[i]->index == ngx_[% subsys %]_lua_module.index) { + ngx_memcpy(cur, + conf_ctx->main_conf[ngx_[% subsys %]_lua_module.ctx_index], + sizeof(ngx_[% subsys %]_lua_main_conf_t)); + } + + [% subsys %]_ctx.main_conf[modules[i]->ctx_index] = cur; + } + if (module->create_srv_conf) { cur = module->create_srv_conf(&conf); if (cur == NULL) { @@ -344,32 +375,17 @@ ngx_[% subsys %]_lua_init_worker(ngx_cycle_t *cycle) } [% END %] -#if defined(nginx_version) && nginx_version >= 1003014 - -# if nginx_version >= 1009000 - +#if defined(nginx_version) && nginx_version >= 1009000 [% IF http_subsys %] ngx_set_connection_log(r->connection, clcf->error_log); [% ELSIF stream_subsys %] ngx_set_connection_log(s->connection, clcf->error_log); [% END %] -# else - +#else [% IF http_subsys %] ngx_http_set_connection_log(r->connection, clcf->error_log); [% END %] - -# endif - -#else - - 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; - } - #endif [% IF http_subsys %] diff --git a/src/subsys/ngx_subsys_lua_input_filters.c.tt2 b/src/subsys/ngx_subsys_lua_input_filters.c.tt2 new file mode 100644 index 0000000..14cb8e7 --- /dev/null +++ b/src/subsys/ngx_subsys_lua_input_filters.c.tt2 @@ -0,0 +1,138 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_[% subsys %]_lua_common.h" + + +ngx_int_t +ngx_[% subsys %]_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *rest, ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if ((size_t) bytes >= *rest) { + + buf_in->buf->last += *rest; + src->pos += *rest; + *rest = 0; + + return NGX_OK; + } + + /* bytes < *rest */ + + buf_in->buf->last += bytes; + src->pos += bytes; + *rest -= bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_[% subsys %]_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_OK; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_AGAIN; +} + + +ngx_int_t +ngx_[% subsys %]_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max, + ssize_t bytes, ngx_log_t *log) +{ + if (bytes == 0) { + return NGX_ERROR; + } + + if (bytes >= (ssize_t) *max) { + bytes = (ssize_t) *max; + } + + buf_in->buf->last += bytes; + src->pos += bytes; + + return NGX_OK; +} + + +ngx_int_t +ngx_[% subsys %]_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log) +{ + u_char *dst; + u_char c; +#if (NGX_DEBUG) + u_char *begin; +#endif + +#if (NGX_DEBUG) + begin = src->pos; +#endif + + if (bytes == 0) { + return NGX_ERROR; + } + + dd("already read: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + dd("data read: %.*s", (int) bytes, src->pos); + + dst = buf_in->buf->last; + + while (bytes--) { + + c = *src->pos++; + + switch (c) { + case '\n': + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, + "[% log_prefix %]lua read the final line part: " + "\"%*s\"", src->pos - 1 - begin, begin); + + buf_in->buf->last = dst; + + dd("read a line: %p: %.*s", buf_in, + (int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos); + + return NGX_OK; + + case '\r': + /* ignore it */ + break; + + default: + *dst++ = c; + break; + } + } + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, + "[% log_prefix %]lua read partial line data: %*s", + dst - begin, begin); +#endif + + buf_in->buf->last = dst; + + return NGX_AGAIN; +} diff --git a/src/subsys/ngx_subsys_lua_input_filters.h.tt2 b/src/subsys/ngx_subsys_lua_input_filters.h.tt2 new file mode 100644 index 0000000..84e27c2 --- /dev/null +++ b/src/subsys/ngx_subsys_lua_input_filters.h.tt2 @@ -0,0 +1,29 @@ + +/* + * Copyright (C) by OpenResty Inc. + */ + + +#ifndef _NGX_[% SUBSYS %]_LUA_INPUT_FILTERS_H_INCLUDED_ +#define _NGX_[% SUBSYS %]_LUA_INPUT_FILTERS_H_INCLUDED_ + + +#include "ngx_[% subsys %]_lua_common.h" + + +ngx_int_t ngx_[% subsys %]_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *rest, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_[% subsys %]_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_[% subsys %]_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, + size_t *max, ssize_t bytes, ngx_log_t *log); + +ngx_int_t ngx_[% subsys %]_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, + ssize_t bytes, ngx_log_t *log); + + +#endif /* _NGX_[% SUBSYS %]_LUA_INPUT_FILTERS_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_log.c.tt2 b/src/subsys/ngx_subsys_lua_log.c.tt2 index 8c7581a..718816a 100644 --- a/src/subsys/ngx_subsys_lua_log.c.tt2 +++ b/src/subsys/ngx_subsys_lua_log.c.tt2 @@ -204,7 +204,7 @@ log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level, *p++ = ':'; p = ngx_snprintf(p, NGX_INT_T_LEN, "%d", - ar.currentline ? ar.currentline : ar.linedefined); + ar.currentline > 0 ? ar.currentline : ar.linedefined); *p++ = ':'; *p++ = ' '; diff --git a/src/subsys/ngx_subsys_lua_misc.c.tt2 b/src/subsys/ngx_subsys_lua_misc.c.tt2 index c6f7a7c..ea1636a 100644 --- a/src/subsys/ngx_subsys_lua_misc.c.tt2 +++ b/src/subsys/ngx_subsys_lua_misc.c.tt2 @@ -12,32 +12,13 @@ #include "ngx_[% subsys %]_lua_misc.h" -#include "ngx_[% subsys %]_lua_ctx.h" #include "ngx_[% subsys %]_lua_util.h" -static int ngx_[% subsys %]_lua_ngx_get(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_set(lua_State *L); - [% IF http_subsys %] static int ngx_[% subsys %]_lua_ngx_req_is_internal(lua_State *L); -[% END %] -void -ngx_[% subsys %]_lua_inject_misc_api(lua_State *L) -{ - /* ngx. getter and setter */ - lua_createtable(L, 0, 2); /* metatable for .ngx */ - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_set); - lua_setfield(L, -2, "__newindex"); - lua_setmetatable(L, -2); -} - - -[% IF http_subsys %] void ngx_[% subsys %]_lua_inject_req_misc_api(lua_State *L) { @@ -62,165 +43,10 @@ ngx_[% subsys %]_lua_ngx_req_is_internal(lua_State *L) [% END %] -static int -ngx_[% subsys %]_lua_ngx_get(lua_State *L) -{ - int status; - [% req_type %] *r; - u_char *p; - size_t len; - ngx_[% subsys %]_lua_ctx_t *ctx; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - lua_pushnil(L); - return 1; - } - - ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); - if (ctx == NULL) { - lua_pushnil(L); - return 1; - } - - p = (u_char *) luaL_checklstring(L, -1, &len); - - dd("ngx get %s", p); - - if (len == sizeof("status") - 1 - && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) - { - ngx_[% subsys %]_lua_check_fake_request(L, r); - -[% IF http_subsys %] - if (r->err_status) { - status = r->err_status; - - } else if (r->headers_out.status) { - status = r->headers_out.status; - - } else if (r->http_version == NGX_HTTP_VERSION_9) { - status = 9; - - } else { - status = 0; - } - -[% ELSIF stream_subsys %] - /* same as $status */ - - status = r->session->status; -[% END %] - - lua_pushinteger(L, status); - return 1; - } - - if (len == sizeof("ctx") - 1 - && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) - { - return ngx_[% subsys %]_lua_ngx_get_ctx(L); - } - -[% IF http_subsys %] - if (len == sizeof("is_subrequest") - 1 - && ngx_strncmp(p, "is_subrequest", sizeof("is_subrequest") - 1) == 0) - { - lua_pushboolean(L, r != r->main); - return 1; - } - - if (len == sizeof("headers_sent") - 1 - && ngx_strncmp(p, "headers_sent", sizeof("headers_sent") - 1) == 0) - { - ngx_[% subsys %]_lua_check_fake_request(L, r); - - dd("headers sent: %d", r->header_sent || ctx->header_sent); - - lua_pushboolean(L, r->header_sent || ctx->header_sent); - return 1; - } -[% END %] - - dd("key %s not matched", p); - - lua_pushnil(L); - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_set(lua_State *L) -{ - [% req_type %] *r; - u_char *p; - size_t len; - - /* we skip the first argument that is the table */ - p = (u_char *) luaL_checklstring(L, 2, &len); - -[% IF http_subsys %] - if (len == sizeof("status") - 1 - && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) - { - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - if (r->header_sent) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "attempt to set ngx.status after sending out " - "response headers"); - return 0; - } - - if (r->err_status) { - r->err_status = 0; - } - - ngx_[% subsys %]_lua_check_fake_request(L, r); - - /* get the value */ - r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); - - 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; - } -[% END %] - - if (len == sizeof("ctx") - 1 - && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) - { - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - return ngx_[% subsys %]_lua_ngx_set_ctx(L); - } - - lua_rawset(L, -3); - return 0; -} - - -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_get_resp_status([% req_type %] *r) { +[% IF http_subsys %] if (r->connection->fd == (ngx_socket_t) -1) { return NGX_[% SUBSYS %]_LUA_FFI_BAD_CONTEXT; } @@ -237,9 +63,14 @@ ngx_[% subsys %]_lua_ffi_get_resp_status([% req_type %] *r) } else { return 0; } + +[% ELSIF stream_subsys %] + return r->session->status; +[% END %] } +[% IF http_subsys %] int ngx_[% subsys %]_lua_ffi_set_resp_status([% req_type %] *r, int status) { @@ -332,9 +163,6 @@ ngx_[% subsys %]_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, return NGX_DECLINED; } -[% IF http_subsys %] -#endif /* NGX_LUA_NO_FFI_API */ -[% END %] /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_misc.h.tt2 b/src/subsys/ngx_subsys_lua_misc.h.tt2 index cace594..1adfb3c 100644 --- a/src/subsys/ngx_subsys_lua_misc.h.tt2 +++ b/src/subsys/ngx_subsys_lua_misc.h.tt2 @@ -12,8 +12,6 @@ #include "ngx_[% subsys %]_lua_common.h" -void ngx_[% subsys %]_lua_inject_misc_api(lua_State *L); - [% IF http_subsys %] void ngx_[% subsys %]_lua_inject_req_misc_api(lua_State *L); [% END %] diff --git a/src/subsys/ngx_subsys_lua_module.c.tt2 b/src/subsys/ngx_subsys_lua_module.c.tt2 index 3f1db6f..e701841 100644 --- a/src/subsys/ngx_subsys_lua_module.c.tt2 +++ b/src/subsys/ngx_subsys_lua_module.c.tt2 @@ -32,6 +32,7 @@ #include "ngx_[% subsys %]_lua_accessby.h" #include "ngx_[% subsys %]_lua_headerfilterby.h" #include "ngx_[% subsys %]_lua_bodyfilterby.h" +#include "ngx_[% subsys %]_lua_pipe.h" [% ELSIF stream_subsys %] #include "ngx_[% subsys %]_lua_prereadby.h" @@ -72,7 +73,7 @@ static volatile ngx_cycle_t *ngx_[% subsys %]_lua_prev_cycle = NULL; [% END %] -#if (NGX_[% SUBSYS %]_SSL) && defined(nginx_version) && nginx_version >= 1001013 +#if (NGX_[% SUBSYS %]_SSL) static ngx_conf_bitmask_t ngx_[% subsys %]_lua_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, @@ -100,9 +101,9 @@ static ngx_command_t ngx_[% subsys %]_lua_cmds[] = { { ngx_string("lua_load_resty_core"), NGX_[% SUBSYS %]_MAIN_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_[% subsys %]_lua_load_resty_core, NGX_[% SUBSYS %]_MAIN_CONF_OFFSET, - offsetof(ngx_[% subsys %]_lua_main_conf_t, load_resty_core), + 0, NULL }, { ngx_string("lua_max_running_timers"), @@ -615,8 +616,6 @@ static ngx_command_t ngx_[% subsys %]_lua_cmds[] = { #if (NGX_[% SUBSYS %]_SSL) -# if defined(nginx_version) && nginx_version >= 1001013 - { ngx_string("lua_ssl_protocols"), [% lua_ssl_flags %]|NGX_CONF_1MORE, ngx_conf_set_bitmask_slot, @@ -624,8 +623,6 @@ static ngx_command_t ngx_[% subsys %]_lua_cmds[] = { offsetof([% lua_ssl_conf_t %], ssl_protocols), &ngx_[% subsys %]_lua_ssl_protocols }, -# endif - { ngx_string("lua_ssl_ciphers"), [% lua_ssl_flags %]|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -721,7 +718,7 @@ static ngx_command_t ngx_[% subsys %]_lua_cmds[] = { ngx_[% subsys %]_module_t ngx_[% subsys %]_lua_module_ctx = { - NULL, /* preconfiguration */ + NULL, /* preconfiguration */ ngx_[% subsys %]_lua_init, /* postconfiguration */ ngx_[% subsys %]_lua_create_main_conf, /* create main configuration */ @@ -741,14 +738,14 @@ ngx_module_t ngx_[% subsys %]_lua_module = { NGX_MODULE_V1, &ngx_[% subsys %]_lua_module_ctx, /* module context */ ngx_[% subsys %]_lua_cmds, /* module directives */ - NGX_[% SUBSYS %]_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ + NGX_[% SUBSYS %]_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ ngx_[% subsys %]_lua_init_worker, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ NGX_MODULE_V1_PADDING }; @@ -758,18 +755,15 @@ ngx_[% subsys %]_lua_init(ngx_conf_t *cf) { ngx_int_t rc; volatile ngx_cycle_t *saved_cycle; - ngx_[% subsys %]_lua_main_conf_t *lmcf; ngx_array_t *arr; + ngx_pool_cleanup_t *cln; + ngx_[% subsys %]_handler_pt *h; + ngx_[% subsys %]_lua_main_conf_t *lmcf; ngx_[% subsys %]_core_main_conf_t *cmcf; [% IF http_subsys %] -#if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 -[% END %] - ngx_pool_cleanup_t *cln; -[% IF http_subsys %] -#endif - + ngx_str_t name = ngx_string("host"); int multi_http_blocks; [% END %] @@ -781,6 +775,11 @@ ngx_[% subsys %]_lua_init(ngx_conf_t *cf) ngx_[% subsys %]_lua_module); [% IF http_subsys %] + lmcf->host_var_index = ngx_[% subsys %]_get_variable_index(cf, &name); + if (lmcf->host_var_index == NGX_ERROR) { + return NGX_ERROR; + } + if (ngx_[% subsys %]_lua_prev_cycle != ngx_cycle) { ngx_[% subsys %]_lua_prev_cycle = ngx_cycle; multi_http_blocks = 0; @@ -880,9 +879,6 @@ ngx_[% subsys %]_lua_init(ngx_conf_t *cf) } [% END # http %] -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] /* add the cleanup of semaphores after the lua_close */ cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { @@ -891,12 +887,15 @@ ngx_[% subsys %]_lua_init(ngx_conf_t *cf) cln->data = lmcf; cln->handler = ngx_[% subsys %]_lua_sema_mm_cleanup; + [% IF http_subsys %] +#ifdef HAVE_NGX_LUA_PIPE + ngx_[% subsys %]_lua_pipe_init(); #endif [% END %] [% IF http_subsys %] -#if nginx_version >= 1011011 +#if defined(nginx_version) && nginx_version >= 1011011 cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_ERROR; @@ -929,14 +928,33 @@ ngx_[% subsys %]_lua_init(ngx_conf_t *cf) ngx_[% subsys %]_lua_location_hash = ngx_[% subsys %]_lua_hash_literal("location"); [% END %] - lmcf->lua = ngx_[% subsys %]_lua_init_vm(NULL, cf->cycle, cf->pool, lmcf, - cf->log, NULL); - if (lmcf->lua == NULL) { - ngx_conf_log_error(NGX_LOG_ERR, cf, 0, - "failed to initialize Lua VM"); - return NGX_ERROR; + rc = ngx_[% subsys %]_lua_init_vm(&lmcf->lua, NULL, cf->cycle, cf->pool, + lmcf, cf->log, NULL); + if (rc != NGX_OK) { + if (rc == NGX_DECLINED) { + ngx_[% subsys %]_lua_assert(lmcf->lua != NULL); + + ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, + "failed to load the 'resty.core' module " + "(https://github.com/openresty/lua-resty" + "-core); ensure you are using an OpenResty " + "release from https://openresty.org/en/" + "download.html (reason: %s)", + lua_tostring(lmcf->lua, -1)); + + } else { + /* rc == NGX_ERROR */ + ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, + "failed to initialize Lua VM"); + } + + return NGX_ERROR; } + /* rc == NGX_OK */ + + ngx_[% subsys %]_lua_assert(lmcf->lua != NULL); + if (!lmcf->requires_shm && lmcf->init_handler) { saved_cycle = ngx_cycle; ngx_cycle = cf->cycle; @@ -990,13 +1008,7 @@ ngx_[% subsys %]_lua_lowat_check(ngx_conf_t *cf, void *post, void *data) static void * ngx_[% subsys %]_lua_create_main_conf(ngx_conf_t *cf) { -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] ngx_int_t rc; -[% IF http_subsys %] -#endif -[% END %] ngx_[% subsys %]_lua_main_conf_t *lmcf; @@ -1030,7 +1042,6 @@ ngx_[% subsys %]_lua_create_main_conf(ngx_conf_t *cf) */ lmcf->pool = cf->pool; - lmcf->load_resty_core = NGX_CONF_UNSET; lmcf->max_pending_timers = NGX_CONF_UNSET; lmcf->max_running_timers = NGX_CONF_UNSET; #if (NGX_PCRE) @@ -1052,18 +1063,12 @@ ngx_[% subsys %]_lua_create_main_conf(ngx_conf_t *cf) lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT; #endif -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] rc = ngx_[% subsys %]_lua_sema_mm_init(cf, lmcf); if (rc != NGX_OK) { return NULL; } dd("nginx Lua module main config structure initialized!"); -[% IF http_subsys %] -#endif -[% END %] return lmcf; } @@ -1074,10 +1079,6 @@ ngx_[% subsys %]_lua_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_[% subsys %]_lua_main_conf_t *lmcf = conf; - if (lmcf->load_resty_core == NGX_CONF_UNSET) { - lmcf->load_resty_core = 1; - } - #if (NGX_PCRE) if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) { lmcf->regex_cache_max_entries = 1024; @@ -1117,15 +1118,11 @@ ngx_[% subsys %]_lua_init_main_conf(ngx_conf_t *cf, void *conf) [% BLOCK merge_common_conf %] #if (NGX_[% SUBSYS %]_SSL) -# if defined(nginx_version) && nginx_version >= 1001013 - ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 |NGX_SSL_TLSv1_2); -# endif - ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); @@ -1228,9 +1225,10 @@ ngx_[% subsys %]_lua_create_srv_conf(ngx_conf_t *cf) static char * ngx_[% subsys %]_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { +#if (NGX_[% SUBSYS %]_SSL) ngx_[% subsys %]_lua_srv_conf_t *prev = parent; ngx_[% subsys %]_lua_srv_conf_t *conf = child; -#if (NGX_[% SUBSYS %]_SSL) + [% IF http_subsys %] ngx_http_ssl_srv_conf_t *sscf; [% ELSIF stream_subsys %] @@ -1289,7 +1287,7 @@ ngx_[% subsys %]_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (sscf && sscf->ssl.ctx) { #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "LibreSSL does not support " + "LibreSSL is not supported by " "ssl_session_store_by_lua*"); return NGX_CONF_ERROR; @@ -1311,7 +1309,7 @@ ngx_[% subsys %]_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (sscf && sscf->ssl.ctx) { #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "LibreSSL does not support " + "LibreSSL is not supported by " "ssl_session_fetch_by_lua*"); return NGX_CONF_ERROR; @@ -1493,26 +1491,13 @@ ngx_stream_lua_set_ssl(ngx_conf_t *cf, ngx_stream_lua_srv_conf_t *lscf) return NGX_ERROR; } - if (lscf->ssl_trusted_certificate.len) { - -#if defined(nginx_version) && nginx_version >= 1003007 - - if (ngx_ssl_trusted_certificate(cf, lscf->ssl, - &lscf->ssl_trusted_certificate, - lscf->ssl_verify_depth) - != NGX_OK) - { - return NGX_ERROR; - } - -#else - - ngx_log_error(NGX_LOG_CRIT, cf->log, 0, "at least nginx 1.3.7 is " - "required for the \"lua_ssl_trusted_certificate\" " - "directive"); + if (lscf->ssl_trusted_certificate.len + && ngx_ssl_trusted_certificate(cf, lscf->ssl, + &lscf->ssl_trusted_certificate, + lscf->ssl_verify_depth) + != NGX_OK) + { return NGX_ERROR; - -#endif } dd("ssl crl: %.*s", (int) lscf->ssl_crl.len, lscf->ssl_crl.data); diff --git a/src/subsys/ngx_subsys_lua_output.c.tt2 b/src/subsys/ngx_subsys_lua_output.c.tt2 index 1eaadb9..10b4edd 100644 --- a/src/subsys/ngx_subsys_lua_output.c.tt2 +++ b/src/subsys/ngx_subsys_lua_output.c.tt2 @@ -623,7 +623,7 @@ ngx_[% subsys %]_lua_ngx_flush(lua_State *L) } [% IF http_subsys %] - cllscf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); + cllscf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); [% ELSIF stream_subsys %] cllscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module); diff --git a/src/subsys/ngx_subsys_lua_phase.c.tt2 b/src/subsys/ngx_subsys_lua_phase.c.tt2 index 37d2dde..ea8a8cc 100644 --- a/src/subsys/ngx_subsys_lua_phase.c.tt2 +++ b/src/subsys/ngx_subsys_lua_phase.c.tt2 @@ -10,14 +10,17 @@ #include "ddebug.h" +[% IF stream_subsys %] #include "ngx_[% subsys %]_lua_phase.h" #include "ngx_[% subsys %]_lua_util.h" #include "ngx_[% subsys %]_lua_ctx.h" - -static int ngx_[% subsys %]_lua_ngx_get_phase(lua_State *L); +[% ELSIF http_subsys %] +#include "ngx_[% subsys %]_lua_common.h" +[% END %] +[% IF stream_subsys %] static int ngx_[% subsys %]_lua_ngx_get_phase(lua_State *L) { @@ -48,40 +51,9 @@ ngx_[% subsys %]_lua_ngx_get_phase(lua_State *L) lua_pushliteral(L, "ssl_cert"); break; -[% IF http_subsys %] - case NGX_[% SUBSYS %]_LUA_CONTEXT_SET: - lua_pushliteral(L, "set"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE: - lua_pushliteral(L, "rewrite"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS: - lua_pushliteral(L, "access"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_HEADER_FILTER: - lua_pushliteral(L, "header_filter"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_BODY_FILTER: - lua_pushliteral(L, "body_filter"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_STORE: - lua_pushliteral(L, "ssl_session_store"); - break; - - case NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH: - lua_pushliteral(L, "ssl_session_fetch"); - break; - -[% ELSIF stream_subsys %] case NGX_STREAM_LUA_CONTEXT_PREREAD: lua_pushliteral(L, "preread"); break; -[% END %] case NGX_[% SUBSYS %]_LUA_CONTEXT_CONTENT: lua_pushliteral(L, "content"); @@ -113,10 +85,10 @@ ngx_[% subsys %]_lua_inject_phase_api(lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_get_phase); lua_setfield(L, -2, "get_phase"); } +[% END %] [% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_get_phase([% req_type %] *r, char **err) { @@ -130,7 +102,6 @@ ngx_[% subsys %]_lua_ffi_get_phase([% req_type %] *r, char **err) return ctx->context; } -#endif [% END # http %] diff --git a/src/subsys/ngx_subsys_lua_phase.h.tt2 b/src/subsys/ngx_subsys_lua_phase.h.tt2 index 041e0c6..4cfbeff 100644 --- a/src/subsys/ngx_subsys_lua_phase.h.tt2 +++ b/src/subsys/ngx_subsys_lua_phase.h.tt2 @@ -5,7 +5,9 @@ #include "ngx_[% subsys %]_lua_common.h" +[% IF stream_subsys %] void ngx_[% subsys %]_lua_inject_phase_api(lua_State *L); +[% END %] #endif /* _NGX_[% SUBSYS %]_LUA_PHASE_H_INCLUDED_ */ diff --git a/src/subsys/ngx_subsys_lua_regex.c.tt2 b/src/subsys/ngx_subsys_lua_regex.c.tt2 index 979a112..d0d625e 100644 --- a/src/subsys/ngx_subsys_lua_regex.c.tt2 +++ b/src/subsys/ngx_subsys_lua_regex.c.tt2 @@ -12,7 +12,6 @@ #if (NGX_PCRE) -#include "ngx_[% subsys %]_lua_regex.h" #include "ngx_[% subsys %]_lua_pcrefix.h" #include "ngx_[% subsys %]_lua_script.h" #include "ngx_[% subsys %]_lua_util.h" @@ -25,10 +24,8 @@ #endif -#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_NO_UTF8_CHECK (1<<4) #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100) @@ -67,7 +64,6 @@ typedef struct { typedef struct { - ngx_[% req_subsys %]_cleanup_pt *cleanup; [% req_type %] *request; pcre *regex; @@ -79,25 +75,10 @@ typedef struct { } ngx_[% subsys %]_lua_regex_ctx_t; -static int ngx_[% subsys %]_lua_ngx_re_gmatch_iterator(lua_State *L); -static ngx_uint_t ngx_[% subsys %]_lua_ngx_re_parse_opts(lua_State *L, - ngx_[% subsys %]_lua_regex_compile_t *re, ngx_str_t *opts, int narg); -static int ngx_[% subsys %]_lua_ngx_re_sub_helper(lua_State *L, unsigned global); -static int ngx_[% subsys %]_lua_ngx_re_match_helper(lua_State *L, int wantcaps); -static int ngx_[% subsys %]_lua_ngx_re_find(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_re_match(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_re_gmatch(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_re_sub(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_re_gsub(lua_State *L); static void ngx_[% subsys %]_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd); static ngx_int_t ngx_[% subsys %]_lua_regex_compile( ngx_[% subsys %]_lua_regex_compile_t *rc); -static void ngx_[% subsys %]_lua_ngx_re_gmatch_cleanup(void *data); -static int ngx_[% subsys %]_lua_ngx_re_gmatch_gc(lua_State *L); -static void ngx_[% subsys %]_lua_re_collect_named_captures(lua_State *L, - int res_tb_idx, u_char *name_table, int name_count, int name_entry_size, - unsigned flags, ngx_str_t *subj); #define ngx_[% subsys %]_lua_regex_exec(re, e, s, start, captures, size, \ @@ -112,1901 +93,6 @@ static void ngx_[% subsys %]_lua_re_collect_named_captures(lua_State *L, captures, size, ws, wscount) -static int -ngx_[% subsys %]_lua_ngx_re_match(lua_State *L) -{ - return ngx_[% subsys %]_lua_ngx_re_match_helper(L, 1 /* want captures */); -} - - -static int -ngx_[% subsys %]_lua_ngx_re_find(lua_State *L) -{ - return ngx_[% subsys %]_lua_ngx_re_match_helper(L, 0 /* want captures */); -} - - -static int -ngx_[% subsys %]_lua_ngx_re_match_helper(lua_State *L, int wantcaps) -{ - /* u_char *p; */ - int res_tb_idx = 0; - [% req_type %] *r; - ngx_str_t subj; - ngx_str_t pat; - ngx_str_t opts; - const char *msg; - ngx_int_t rc; - ngx_uint_t n; - int i; - ngx_int_t pos = 0; - int nargs; - int *cap = NULL; - int ovecsize; - int has_ctx = 0; - ngx_uint_t flags; - ngx_pool_t *pool, *old_pool; - u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; - pcre_extra *sd = NULL; - int name_entry_size = 0, name_count; - u_char *name_table = NULL; - int exec_opts; - int group_id = 0; - - ngx_[% subsys %]_lua_regex_t *re; - ngx_[% subsys %]_lua_main_conf_t *lmcf; - ngx_[% subsys %]_lua_regex_compile_t re_comp; - - nargs = lua_gettop(L); - - if (nargs != 2 && nargs != 3 && nargs != 4 && nargs != 5) { - return luaL_error(L, "expecting 2, 3, 4 or 5 arguments, " - "but got %d", nargs); - } - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - 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_[% subsys %]_lua_regex_compile_t)); - - if (nargs >= 3) { - opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); - - if (nargs >= 4) { - if (!lua_isnil(L, 4)) { - luaL_checktype(L, 4, LUA_TTABLE); - has_ctx = 1; - - lua_getfield(L, 4, "pos"); - if (lua_isnumber(L, -1)) { - pos = (ngx_int_t) lua_tointeger(L, -1); - if (pos <= 0) { - pos = 0; - - } else { - pos--; /* 1-based on the Lua land */ - } - - } else if (lua_isnil(L, -1)) { - pos = 0; - - } else { - msg = lua_pushfstring(L, "bad pos field type in the ctx " - "table argument: %s", - luaL_typename(L, -1)); - - return luaL_argerror(L, 4, msg); - } - - lua_pop(L, 1); - } - } - - } else { - opts.data = (u_char *) ""; - opts.len = 0; - } - - if (nargs == 5) { - if (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) { - lua_pop(L, 1); - lua_pushvalue(L, -1); - lua_pushnil(L); - lua_rawset(L, res_tb_idx); - } -#endif - - } else { - group_id = luaL_checkint(L, 5); - if (group_id < 0) { - group_id = 0; - } - } - } - - re_comp.options = 0; - - flags = ngx_[% subsys %]_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); - - lmcf = ngx_[% req_subsys %]_get_module_main_conf(r, ngx_[% subsys %]_lua_module); - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - pool = lmcf->pool; - - dd("server pool %p", lmcf->pool); - - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - regex_cache_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - - lua_pushliteral(L, "m"); - lua_pushvalue(L, 2); /* table regex */ - - dd("options size: %d", (int) sizeof(re_comp.options)); - - lua_pushlstring(L, (char *) &re_comp.options, 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_rawget(L, -3); /* table key re */ - re = lua_touserdata(L, -1); - - lua_pop(L, 1); /* table key */ - - if (re) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "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_comp.regex = re->regex; - sd = re->regex_sd; - re_comp.captures = re->ncaptures; - cap = re->captures; - - if (flags & NGX_LUA_RE_MODE_DFA) { - ovecsize = 2; - - } else { - ovecsize = (re->ncaptures + 1) * 3; - } - - goto exec; - } - - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "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); - - lmcf->regex_cache_entries++; - } - - pool = r->pool; - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - } - - } else { - pool = r->pool; - } - - dd("pool %p, r pool %p", pool, r->pool); - - re_comp.pattern = pat; - re_comp.err.len = NGX_MAX_CONF_ERRSTR; - re_comp.err.data = errstr; - re_comp.pool = pool; - - ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], 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); - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - rc = ngx_[% subsys %]_lua_regex_compile(&re_comp); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - if (rc != NGX_OK) { - dd("compile failed"); - - lua_pushnil(L); - if (!wantcaps) { - lua_pushnil(L); - } - lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); - return wantcaps ? 2 : 3; - } - -#if (LUA_HAVE_PCRE_JIT) - - if (flags & NGX_LUA_RE_MODE_JIT) { - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); - - if (sd && lmcf->jit_stack) { - pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); - } - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } - - if (sd != NULL) { - int jitted; - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); - } -# endif /* !(NGX_DEBUG) */ - - } else { - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, 0, &msg); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } -# endif /* NGX_DEBUG */ - } - -#else /* !(LUA_HAVE_PCRE_JIT) */ - - if (flags & NGX_LUA_RE_MODE_JIT) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); - } - -#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) { - ovecsize = 2; - re_comp.captures = 0; - - } 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) { - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "no memory"; - goto error; - } - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua saving compiled regex (%d captures) into the cache " - "(entries %i)", re_comp.captures, - lmcf->regex_cache_entries); - - re = ngx_palloc(pool, sizeof(ngx_[% subsys %]_lua_regex_t)); - if (re == NULL) { - msg = "no memory"; - goto error; - } - - dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); - - re->regex = re_comp.regex; - re->regex_sd = sd; - re->ncaptures = re_comp.captures; - re->captures = cap; - re->replace = NULL; - - lua_pushlightuserdata(L, re); /* table key value */ - lua_rawset(L, -3); /* table */ - lua_pop(L, 1); - - if (lmcf) { - lmcf->regex_cache_entries++; - } - } - -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_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 - - int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; - rc = ngx_[% subsys %]_lua_regex_dfa_exec(re_comp.regex, sd, &subj, - (int) pos, cap, ovecsize, ws, - sizeof(ws)/sizeof(ws[0]), exec_opts); - -#else /* LUA_HAVE_PCRE_DFA */ - - msg = "at least pcre 6.0 is required for the DFA mode"; - goto error; - -#endif /* LUA_HAVE_PCRE_DFA */ - - } else { - rc = ngx_[% subsys %]_lua_regex_exec(re_comp.regex, sd, &subj, (int) pos, cap, - ovecsize, exec_opts); - } - - if (rc == NGX_REGEX_NO_MATCHED) { - ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "regex \"%V\" not matched on string \"%V\" starting " - "from %i", &pat, &subj, pos); - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - ngx_pfree(pool, re_comp.regex); - ngx_pfree(pool, cap); - } - - lua_pushnil(L); - return 1; - } - - if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc); - goto error; - } - - if (rc == 0) { - if (flags & NGX_LUA_RE_MODE_DFA) { - rc = 1; - - } else { - msg = "capture size too small"; - goto error; - } - } - - dd("rc = %d", (int) rc); - - if (has_ctx) { /* having ctx table */ - pos = cap[1]; - lua_pushinteger(L, (lua_Integer) (pos + 1)); - lua_setfield(L, 4, "pos"); - } - - if (!wantcaps) { - if (group_id > re_comp.captures) { - lua_pushnil(L); - lua_pushnil(L); - lua_pushliteral(L, "nth out of bound"); - return 3; - } - - if (group_id >= rc) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - - { - int from, to; - - from = cap[group_id * 2] + 1; - to = cap[group_id * 2 + 1]; - if (from < 0 || to < 0) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - - lua_pushinteger(L, from); - lua_pushinteger(L, to); - return 2; - } - } - - if (res_tb_idx == 0) { - lua_createtable(L, re_comp.captures || 1 /* narr */, - name_count /* nrec */); - res_tb_idx = lua_gettop(L); - } - - for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) { - dd("capture %d: %d %d", i, cap[n], cap[n + 1]); - if (i >= rc || cap[n] < 0) { - lua_pushboolean(L, 0); - - } else { - lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); - - dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); - } - - lua_rawseti(L, res_tb_idx, (int) i); - } - - if (name_count > 0) { - ngx_[% subsys %]_lua_re_collect_named_captures(L, res_tb_idx, name_table, - name_count, name_entry_size, - flags, &subj); - } - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - ngx_pfree(pool, re_comp.regex); - ngx_pfree(pool, cap); - } - - return 1; - -error: - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - if (re_comp.regex) { - ngx_pfree(pool, re_comp.regex); - } - - if (cap) { - ngx_pfree(pool, cap); - } - } - - lua_pushnil(L); - if (!wantcaps) { - lua_pushnil(L); - } - lua_pushstring(L, msg); - return wantcaps ? 2 : 3; -} - - -static int -ngx_[% subsys %]_lua_ngx_re_gmatch(lua_State *L) -{ - [% req_type %] *r; - ngx_str_t subj; - ngx_str_t pat; - ngx_str_t opts; - int ovecsize; - const char *msg; - int nargs; - ngx_int_t flags; - int *cap = NULL; - ngx_int_t rc; - ngx_pool_t *pool, *old_pool; - u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; - pcre_extra *sd = NULL; - - ngx_[% subsys %]_lua_regex_t *re; - ngx_[% subsys %]_lua_regex_ctx_t *ctx; - ngx_[% subsys %]_lua_main_conf_t *lmcf; - ngx_[% req_subsys %]_cleanup_t *cln; - ngx_[% subsys %]_lua_regex_compile_t re_comp; - - nargs = lua_gettop(L); - - if (nargs != 2 && nargs != 3) { - return luaL_error(L, "expecting two or three arguments, but got %d", - nargs); - } - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); - pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); - - if (nargs == 3) { - opts.data = (u_char *) luaL_checklstring(L, 3, &opts.len); - lua_pop(L, 1); - - } else { - opts.data = (u_char *) ""; - opts.len = 0; - } - - /* stack: subj regex */ - - re_comp.options = 0; - - flags = ngx_[% subsys %]_lua_ngx_re_parse_opts(L, &re_comp, &opts, 3); - - lmcf = ngx_[% req_subsys %]_get_module_main_conf(r, ngx_[% subsys %]_lua_module); - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - pool = lmcf->pool; - - dd("server pool %p", lmcf->pool); - - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - regex_cache_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - - lua_pushliteral(L, "m"); - lua_pushvalue(L, 2); /* table regex */ - - dd("options size: %d", (int) sizeof(re_comp.options)); - - lua_pushlstring(L, (char *) &re_comp.options, - 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_rawget(L, -3); /* table key re */ - re = lua_touserdata(L, -1); - - lua_pop(L, 1); /* table key */ - - if (re) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "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_comp.regex = re->regex; - sd = re->regex_sd; - re_comp.captures = re->ncaptures; - cap = re->captures; - - if (flags & NGX_LUA_RE_MODE_DFA) { - ovecsize = 2; - - } else { - ovecsize = (re->ncaptures + 1) * 3; - } - - goto compiled; - } - - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "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); - - lmcf->regex_cache_entries++; - } - - pool = r->pool; - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - } - - } else { - pool = r->pool; - } - - re_comp.pattern = pat; - re_comp.err.len = NGX_MAX_CONF_ERRSTR; - re_comp.err.data = errstr; - re_comp.pool = pool; - - ngx_log_debug5(NGX_LOG_DEBUG_[% SUBSYS %], 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); - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - rc = ngx_[% subsys %]_lua_regex_compile(&re_comp); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - if (rc != NGX_OK) { - dd("compile failed"); - - lua_pushnil(L); - lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); - return 2; - } - -#if LUA_HAVE_PCRE_JIT - - if (flags & NGX_LUA_RE_MODE_JIT) { - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); - - if (sd && lmcf->jit_stack) { - pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); - } - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } - - if (sd != NULL) { - int jitted; - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); - } -# endif /* NGX_DEBUG */ - - } else { - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, 0, &msg); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } -# endif /* NGX_DEBUG */ - } - -#else /* LUA_HAVE_PCRE_JIT */ - - if (flags & NGX_LUA_RE_MODE_JIT) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); - } - -#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) { - ovecsize = 2; - re_comp.captures = 0; - - } else { - ovecsize = (re_comp.captures + 1) * 3; - } - - cap = ngx_palloc(pool, ovecsize * sizeof(int)); - if (cap == NULL) { - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "no memory"; - goto error; - } - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua saving compiled regex (%d captures) into the cache " - "(entries %i)", re_comp.captures, - lmcf->regex_cache_entries); - - re = ngx_palloc(pool, sizeof(ngx_[% subsys %]_lua_regex_t)); - if (re == NULL) { - msg = "no memory"; - goto error; - } - - dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); - - re->regex = re_comp.regex; - re->regex_sd = sd; - re->ncaptures = re_comp.captures; - re->captures = cap; - re->replace = NULL; - - lua_pushlightuserdata(L, re); /* table key value */ - lua_rawset(L, -3); /* table */ - lua_pop(L, 1); - - if (lmcf) { - lmcf->regex_cache_entries++; - } - } - -compiled: - - lua_settop(L, 1); - - ctx = lua_newuserdata(L, sizeof(ngx_[% subsys %]_lua_regex_ctx_t)); - - ctx->request = r; - ctx->regex = re_comp.regex; - ctx->regex_sd = sd; - ctx->ncaptures = re_comp.captures; - ctx->captures = cap; - ctx->captures_len = ovecsize; - ctx->flags = (uint8_t) flags; - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_gmatch_gc); - lua_setfield(L, -2, "__gc"); - lua_setmetatable(L, -2); - - cln = ngx_[% req_subsys %]_cleanup_add(r, 0); - if (cln == NULL) { - msg = "no memory"; - goto error; - } - - cln->handler = ngx_[% subsys %]_lua_ngx_re_gmatch_cleanup; - cln->data = ctx; - ctx->cleanup = &cln->handler; - - } else { - ctx->cleanup = NULL; - } - - lua_pushinteger(L, 0); - - /* upvalues in order: subj ctx offset */ - lua_pushcclosure(L, ngx_[% subsys %]_lua_ngx_re_gmatch_iterator, 3); - - return 1; - -error: - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - if (re_comp.regex) { - ngx_pfree(pool, re_comp.regex); - } - - if (cap) { - ngx_pfree(pool, cap); - } - } - - lua_pushnil(L); - lua_pushstring(L, msg); - return 2; -} - - -static int -ngx_[% subsys %]_lua_ngx_re_gmatch_iterator(lua_State *L) -{ - [% req_type %] *r; - int *cap; - ngx_int_t rc; - ngx_uint_t n; - int i; - ngx_str_t subj; - int offset; - const char *msg = NULL; - int name_entry_size = 0, name_count; - u_char *name_table = NULL; - int exec_opts; - - ngx_[% subsys %]_lua_regex_ctx_t *ctx; - - /* upvalues in order: subj ctx offset */ - - subj.data = (u_char *) lua_tolstring(L, lua_upvalueindex(1), &subj.len); - ctx = (ngx_[% subsys %]_lua_regex_ctx_t *) lua_touserdata(L, lua_upvalueindex(2)); - offset = (int) lua_tointeger(L, lua_upvalueindex(3)); - - if (offset < 0) { - lua_pushnil(L); - return 1; - } - - cap = ctx->captures; - - dd("offset %d, r %p, subj %s", (int) offset, ctx->request, subj.data); - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - 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"); - } - - 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_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 - - int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; - - rc = ngx_[% subsys %]_lua_regex_dfa_exec(ctx->regex, ctx->regex_sd, &subj, - offset, cap, ctx->captures_len, ws, - sizeof(ws)/sizeof(ws[0]), exec_opts); - -#else /* LUA_HAVE_PCRE_DFA */ - msg = "at least pcre 6.0 is required for the DFA mode"; - goto error; - -#endif /* LUA_HAVE_PCRE_DFA */ - - } else { - rc = ngx_[% subsys %]_lua_regex_exec(ctx->regex, ctx->regex_sd, &subj, - offset, cap, ctx->captures_len, - exec_opts); - } - - if (rc == NGX_REGEX_NO_MATCHED) { - /* set upvalue "offset" to -1 */ - lua_pushinteger(L, -1); - lua_replace(L, lua_upvalueindex(3)); - - if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (ctx->regex_sd) { - ngx_[% subsys %]_lua_regex_free_study_data(r->pool, ctx->regex_sd); - ctx->regex_sd = NULL; - } - - ngx_pfree(r->pool, cap); - } - - lua_pushnil(L); - return 1; - } - - if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", (int) rc); - goto error; - } - - if (rc == 0) { - if (ctx->flags & NGX_LUA_RE_MODE_DFA) { - rc = 1; - - } else { - goto error; - } - } - - dd("rc = %d", (int) rc); - - lua_createtable(L, ctx->ncaptures || 1 /* narr */, name_count /* nrec */); - - for (i = 0, n = 0; i <= ctx->ncaptures; i++, n += 2) { - dd("capture %d: %d %d", i, cap[n], cap[n + 1]); - if (i >= rc || cap[n] < 0) { - lua_pushboolean(L, 0); - - } else { - lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); - - dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); - } - - lua_rawseti(L, -2, (int) i); - } - - if (name_count > 0) { - ngx_[% subsys %]_lua_re_collect_named_captures(L, lua_gettop(L), name_table, - name_count, name_entry_size, - ctx->flags, &subj); - } - - offset = cap[1]; - if (offset == cap[0]) { - offset++; - } - - if (offset > (ssize_t) subj.len) { - offset = -1; - - if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (ctx->regex_sd) { - ngx_[% subsys %]_lua_regex_free_study_data(r->pool, ctx->regex_sd); - ctx->regex_sd = NULL; - } - - ngx_pfree(r->pool, cap); - } - } - - lua_pushinteger(L, offset); - lua_replace(L, lua_upvalueindex(3)); - - return 1; - -error: - - lua_pushinteger(L, -1); - lua_replace(L, lua_upvalueindex(3)); - - if (!(ctx->flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (ctx->regex_sd) { - ngx_[% subsys %]_lua_regex_free_study_data(r->pool, ctx->regex_sd); - ctx->regex_sd = NULL; - } - - ngx_pfree(r->pool, cap); - } - - lua_pushnil(L); - lua_pushstring(L, msg); - return 2; -} - - -static ngx_uint_t -ngx_[% subsys %]_lua_ngx_re_parse_opts(lua_State *L, - ngx_[% subsys %]_lua_regex_compile_t *re, ngx_str_t *opts, int narg) -{ - u_char *p; - const char *msg; - ngx_uint_t flags; - - flags = 0; - p = opts->data; - - while (*p != '\0') { - switch (*p) { - case 'i': - re->options |= NGX_REGEX_CASELESS; - break; - - case 's': - re->options |= PCRE_DOTALL; - break; - - case 'm': - re->options |= PCRE_MULTILINE; - break; - - case 'u': - 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; - - case 'o': - flags |= NGX_LUA_RE_COMPILE_ONCE; - break; - - case 'j': - flags |= NGX_LUA_RE_MODE_JIT; - break; - - case 'd': - flags |= NGX_LUA_RE_MODE_DFA; - break; - - case 'a': - 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; - break; - - case 'J': - re->options |= PCRE_JAVASCRIPT_COMPAT; - break; -#endif - - default: - msg = lua_pushfstring(L, "unknown flag \"%c\" (flags \"%s\")", - *p, opts->data); - return luaL_argerror(L, narg, msg); - } - - p++; - } - - /* pcre does not support JIT for DFA mode yet, - * so if DFA mode is specified, we turn off JIT automatically - * */ - if ((flags & NGX_LUA_RE_MODE_JIT) && (flags & NGX_LUA_RE_MODE_DFA)) { - flags &= ~NGX_LUA_RE_MODE_JIT; - } - - return flags; -} - - -static int -ngx_[% subsys %]_lua_ngx_re_sub(lua_State *L) -{ - return ngx_[% subsys %]_lua_ngx_re_sub_helper(L, 0 /* global */); -} - - -static int -ngx_[% subsys %]_lua_ngx_re_gsub(lua_State *L) -{ - return ngx_[% subsys %]_lua_ngx_re_sub_helper(L, 1 /* global */); -} - - -static int -ngx_[% subsys %]_lua_ngx_re_sub_helper(lua_State *L, unsigned global) -{ - [% req_type %] *r; - ngx_str_t subj; - ngx_str_t pat; - ngx_str_t opts; - ngx_str_t tpl; - ngx_pool_t *pool, *old_pool; - const char *msg; - ngx_int_t rc; - ngx_uint_t n; - ngx_int_t i; - int nargs; - int *cap = NULL; - int ovecsize; - int type; - unsigned func; - int offset; - int cp_offset; - size_t count; - luaL_Buffer luabuf; - ngx_int_t flags; - u_char *p; - u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; - pcre_extra *sd = NULL; - int name_entry_size = 0, name_count; - u_char *name_table = NULL; - int exec_opts; - - ngx_[% subsys %]_lua_main_conf_t *lmcf; - ngx_[% subsys %]_lua_regex_t *re; - ngx_[% subsys %]_lua_regex_compile_t re_comp; - ngx_[% subsys %]_lua_complex_value_t *ctpl = NULL; - ngx_[% subsys %]_lua_compile_complex_value_t ccv; - - nargs = lua_gettop(L); - - if (nargs != 3 && nargs != 4) { - return luaL_error(L, "expecting three or four arguments, but got %d", - nargs); - } - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); - pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); - - func = 0; - - type = lua_type(L, 3); - switch (type) { - case LUA_TFUNCTION: - func = 1; - tpl.len = 0; - tpl.data = (u_char *) ""; - break; - - case LUA_TNUMBER: - case LUA_TSTRING: - tpl.data = (u_char *) lua_tolstring(L, 3, &tpl.len); - break; - - default: - msg = lua_pushfstring(L, "string, number, or function expected, " - "got %s", lua_typename(L, type)); - return luaL_argerror(L, 3, msg); - } - - ngx_memzero(&re_comp, sizeof(ngx_[% subsys %]_lua_regex_compile_t)); - - if (nargs == 4) { - opts.data = (u_char *) luaL_checklstring(L, 4, &opts.len); - lua_pop(L, 1); - - } else { /* nargs == 3 */ - opts.data = (u_char *) ""; - opts.len = 0; - } - - /* stack: subj regex repl */ - - re_comp.options = 0; - - flags = ngx_[% subsys %]_lua_ngx_re_parse_opts(L, &re_comp, &opts, 4); - - lmcf = ngx_[% req_subsys %]_get_module_main_conf(r, ngx_[% subsys %]_lua_module); - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - pool = lmcf->pool; - - dd("server pool %p", lmcf->pool); - - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - regex_cache_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - - lua_pushliteral(L, "s"); - lua_pushinteger(L, tpl.len); - lua_pushliteral(L, ":"); - lua_pushvalue(L, 2); - - if (tpl.len != 0) { - lua_pushvalue(L, 3); - } - - dd("options size: %d", (int) sizeof(re_comp.options)); - - lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options)); - /* table regex opts */ - - if (tpl.len == 0) { - lua_concat(L, 5); /* table key */ - - } else { - lua_concat(L, 6); /* 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_rawget(L, -3); /* table key re */ - re = lua_touserdata(L, -1); - - lua_pop(L, 1); /* table key */ - - if (re) { - ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], 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_pop(L, 2); - - dd("restoring regex %p, ncaptures %d, captures %p", re->regex, - re->ncaptures, re->captures); - - re_comp.regex = re->regex; - sd = re->regex_sd; - re_comp.captures = re->ncaptures; - cap = re->captures; - ctpl = re->replace; - - if (flags & NGX_LUA_RE_MODE_DFA) { - ovecsize = 2; - - } else { - ovecsize = (re->ncaptures + 1) * 3; - } - - goto exec; - } - - ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], 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); - - 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); - - lmcf->regex_cache_entries++; - } - - pool = r->pool; - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - } - - } else { - pool = r->pool; - } - - re_comp.pattern = pat; - re_comp.err.len = NGX_MAX_CONF_ERRSTR; - re_comp.err.data = errstr; - re_comp.pool = pool; - - dd("compiling regex"); - - ngx_log_debug6(NGX_LOG_DEBUG_[% SUBSYS %], 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); - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - rc = ngx_[% subsys %]_lua_regex_compile(&re_comp); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - if (rc != NGX_OK) { - dd("compile failed"); - - lua_pushnil(L); - lua_pushnil(L); - lua_pushlstring(L, (char *) re_comp.err.data, re_comp.err.len); - return 3; - } - -#if LUA_HAVE_PCRE_JIT - - if (flags & NGX_LUA_RE_MODE_JIT) { - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } - - if (sd != NULL) { - int jitted; - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre JIT compiling result: %d", jitted); - } -# endif /* NGX_DEBUG */ - - } else { - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - sd = pcre_study(re_comp.regex, 0, &msg); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - -# if (NGX_DEBUG) - dd("sd = %p", sd); - - if (msg != NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "pcre_study failed with PCRE_STUDY_JIT_COMPILE: " - "%s (%p)", msg, sd); - } -# endif /* NGX_DEBUG */ - } - -#else /* LUA_HAVE_PCRE_JIT */ - - if (flags & NGX_LUA_RE_MODE_JIT) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "your pcre build does not have JIT support and " - "the \"j\" regex option is ignored"); - } - -#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) { - ovecsize = 2; - re_comp.captures = 0; - - } else { - ovecsize = (re_comp.captures + 1) * 3; - } - - cap = ngx_palloc(pool, ovecsize * sizeof(int)); - if (cap == NULL) { - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "no memory"; - goto error; - } - - if (func) { - ctpl = NULL; - - } else { - ctpl = ngx_palloc(pool, sizeof(ngx_[% subsys %]_lua_complex_value_t)); - if (ctpl == NULL) { - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "no memory"; - goto error; - } - - if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { - /* copy the string buffer pointed to by tpl.data from Lua VM */ - p = ngx_palloc(pool, tpl.len + 1); - if (p == NULL) { - flags &= ~NGX_LUA_RE_COMPILE_ONCE; - msg = "no memory"; - goto error; - } - - ngx_memcpy(p, tpl.data, tpl.len); - p[tpl.len] = '\0'; - - tpl.data = p; - } - - ngx_memzero(&ccv, sizeof(ngx_[% subsys %]_lua_compile_complex_value_t)); - ccv.pool = pool; - ccv.log = r->connection->log; - ccv.value = &tpl; - ccv.complex_value = ctpl; - - if (ngx_[% subsys %]_lua_compile_complex_value(&ccv) != NGX_OK) { - ngx_pfree(pool, cap); - ngx_pfree(pool, ctpl); - - if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { - ngx_pfree(pool, tpl.data); - } - - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - ngx_pfree(pool, re_comp.regex); - - lua_pushnil(L); - lua_pushnil(L); - lua_pushliteral(L, "failed to compile the replacement template"); - return 3; - } - } - - if (flags & NGX_LUA_RE_COMPILE_ONCE) { - - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua saving compiled sub regex (%d captures) into " - "the cache (entries %i)", re_comp.captures, - lmcf->regex_cache_entries); - - re = ngx_palloc(pool, sizeof(ngx_[% subsys %]_lua_regex_t)); - if (re == NULL) { - msg = "no memory"; - goto error; - } - - dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, - re_comp.captures, cap); - - re->regex = re_comp.regex; - re->regex_sd = sd; - re->ncaptures = re_comp.captures; - re->captures = cap; - re->replace = ctpl; - - lua_pushlightuserdata(L, re); /* table key value */ - lua_rawset(L, -3); /* table */ - lua_pop(L, 1); - - if (lmcf) { - lmcf->regex_cache_entries++; - } - } - -exec: - - count = 0; - 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; - } - } - - 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) { - -#if LUA_HAVE_PCRE_DFA - - int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; - rc = ngx_[% subsys %]_lua_regex_dfa_exec(re_comp.regex, sd, &subj, - offset, cap, ovecsize, ws, - sizeof(ws)/sizeof(ws[0]), - exec_opts); - -#else /* LUA_HAVE_PCRE_DFA */ - - msg = "at least pcre 6.0 is required for the DFA mode"; - goto error; - -#endif /* LUA_HAVE_PCRE_DFA */ - - } else { - rc = ngx_[% subsys %]_lua_regex_exec(re_comp.regex, sd, &subj, - offset, cap, ovecsize, - exec_opts); - } - - if (rc == NGX_REGEX_NO_MATCHED) { - break; - } - - if (rc < 0) { - msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d", - (int) rc); - goto error; - } - - if (rc == 0) { - if (flags & NGX_LUA_RE_MODE_DFA) { - rc = 1; - - } else { - msg = "capture size too small"; - goto error; - } - } - - dd("rc = %d", (int) rc); - - count++; - - if (count == 1) { - luaL_buffinit(L, &luabuf); - } - - if (func) { - lua_pushvalue(L, 3); - - lua_createtable(L, re_comp.captures || 1 /* narr */, - name_count /* nrec */); - - for (i = 0, n = 0; i <= re_comp.captures; i++, n += 2) { - dd("capture %d: %d %d", (int) i, cap[n], cap[n + 1]); - if (i >= rc || cap[n] < 0) { - lua_pushboolean(L, 0); - - } else { - lua_pushlstring(L, (char *) &subj.data[cap[n]], - cap[n + 1] - cap[n]); - - dd("pushing capture %s at %d", lua_tostring(L, -1), - (int) i); - } - - lua_rawseti(L, -2, (int) i); - } - - if (name_count > 0) { - ngx_[% subsys %]_lua_re_collect_named_captures(L, lua_gettop(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 */); - type = lua_type(L, -1); - switch (type) { - case LUA_TNUMBER: - case LUA_TSTRING: - tpl.data = (u_char *) lua_tolstring(L, -1, &tpl.len); - break; - - default: - msg = lua_pushfstring(L, "string or number expected to be " - "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); - - luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); - - lua_remove(L, 1); - - cp_offset = cap[1]; - offset = cp_offset; - if (offset == cap[0]) { - offset++; - if (offset > (ssize_t) subj.len) { - break; - } - } - - if (global) { - continue; - } - - break; - } - - rc = ngx_[% subsys %]_lua_complex_value(r, &subj, cp_offset, rc, cap, ctpl, - &luabuf); - - if (rc != NGX_OK) { - msg = lua_pushfstring(L, "failed to eval the template for " - "replacement: \"%s\"", tpl.data); - goto error; - } - - cp_offset = cap[1]; - offset = cp_offset; - if (offset == cap[0]) { - offset++; - if (offset > (ssize_t) subj.len) { - break; - } - } - - if (global) { - continue; - } - - break; - } - - if (count == 0) { - dd("no match, just the original subject"); - lua_settop(L, 1); - - } else { - if (offset < (int) subj.len) { - dd("adding trailer: %s (len %d)", &subj.data[cp_offset], - (int) (subj.len - cp_offset)); - - - luaL_addlstring(&luabuf, (char *) &subj.data[cp_offset], - subj.len - cp_offset); - } - - luaL_pushresult(&luabuf); - - dd("the dst string: %s", lua_tostring(L, -1)); - } - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - if (re_comp.regex) { - ngx_pfree(pool, re_comp.regex); - } - - if (ctpl) { - ngx_pfree(pool, ctpl); - } - - if (cap) { - ngx_pfree(pool, cap); - } - } - - lua_pushinteger(L, count); - return 2; - -error: - - if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { - if (sd) { - ngx_[% subsys %]_lua_regex_free_study_data(pool, sd); - } - - if (re_comp.regex) { - ngx_pfree(pool, re_comp.regex); - } - - if (ctpl) { - ngx_pfree(pool, ctpl); - } - - if (cap) { - ngx_pfree(pool, cap); - } - } - - lua_pushnil(L); - lua_pushnil(L); - lua_pushstring(L, msg); - return 3; -} - - -ngx_int_t -ngx_[% subsys %]_lua_ffi_set_jit_stack_size(int size, u_char *errstr, - size_t *errstr_size) -{ -#if LUA_HAVE_PCRE_JIT - - ngx_[% subsys %]_lua_main_conf_t *lmcf; - ngx_pool_t *pool, *old_pool; - - lmcf = ngx_[% subsys %]_cycle_get_module_main_conf(ngx_cycle, - ngx_[% subsys %]_lua_module); - - if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { - size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; - } - - pool = lmcf->pool; - - dd("server pool %p", lmcf->pool); - - if (lmcf->jit_stack) { - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - pcre_jit_stack_free(lmcf->jit_stack); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - } - - old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - - lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, - size); - - ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - - if (lmcf->jit_stack == NULL) { - *errstr_size = ngx_snprintf(errstr, *errstr_size, - "pcre jit stack allocation failed") - - errstr; - return NGX_ERROR; - } - - return NGX_OK; - -#else /* LUA_HAVE_PCRE_JIT */ - - *errstr_size = ngx_snprintf(errstr, *errstr_size, - "no pcre jit support found") - errstr; - return NGX_ERROR; - -#endif /* LUA_HAVE_PCRE_JIT */ -} - - -void -ngx_[% subsys %]_lua_inject_regex_api(lua_State *L) -{ - /* ngx.re */ - - lua_createtable(L, 0, 5 /* nrec */); /* .re */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_find); - lua_setfield(L, -2, "find"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_match); - lua_setfield(L, -2, "match"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_gmatch); - lua_setfield(L, -2, "gmatch"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_sub); - lua_setfield(L, -2, "sub"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_re_gsub); - lua_setfield(L, -2, "gsub"); - - lua_setfield(L, -2, "re"); -} - - static void ngx_[% subsys %]_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd) { @@ -2078,104 +164,57 @@ failed: } -static void -ngx_[% subsys %]_lua_ngx_re_gmatch_cleanup(void *data) +ngx_int_t +ngx_[% subsys %]_lua_ffi_set_jit_stack_size(int size, u_char *errstr, + size_t *errstr_size) { - ngx_[% subsys %]_lua_regex_ctx_t *ctx = data; +#if LUA_HAVE_PCRE_JIT - if (ctx) { - if (ctx->regex_sd) { - ngx_[% subsys %]_lua_regex_free_study_data(ctx->request->pool, - ctx->regex_sd); - ctx->regex_sd = NULL; - } + ngx_[% subsys %]_lua_main_conf_t *lmcf; + ngx_pool_t *pool, *old_pool; - if (ctx->cleanup) { - *ctx->cleanup = NULL; - ctx->cleanup = NULL; - } + lmcf = ngx_[% subsys %]_cycle_get_module_main_conf(ngx_cycle, + ngx_[% subsys %]_lua_module); - ctx->request = NULL; + if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { + size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; } - return; -} + pool = lmcf->pool; + dd("server pool %p", lmcf->pool); -static int -ngx_[% subsys %]_lua_ngx_re_gmatch_gc(lua_State *L) -{ - ngx_[% subsys %]_lua_regex_ctx_t *ctx; + if (lmcf->jit_stack) { + old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - ctx = lua_touserdata(L, 1); + pcre_jit_stack_free(lmcf->jit_stack); - if (ctx && ctx->cleanup) { - ngx_[% subsys %]_lua_ngx_re_gmatch_cleanup(ctx); + ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); } - return 0; -} - - -static void -ngx_[% subsys %]_lua_re_collect_named_captures(lua_State *L, int res_tb_idx, - 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++) { - 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) { - /* unmatched groups are not stored in tables in DUPNAMES mode */ - if (!lua_toboolean(L, -1)) { - lua_pop(L, 1); - continue; - } + old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(pool); - lua_getfield(L, -2, name); /* big_tb cap small_tb */ + lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, + size); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); + ngx_[% subsys %]_lua_pcre_malloc_done(old_pool); - /* assuming named submatches are usually unique */ - lua_createtable(L, 1 /* narr */, 0 /* nrec */); - lua_pushstring(L, name); - lua_pushvalue(L, -2); /* big_tb cap small_tb key small_tb */ - lua_rawset(L, res_tb_idx); /* big_tb cap small_tb */ - len = 0; + if (lmcf->jit_stack == NULL) { + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "pcre jit stack allocation failed") + - errstr; + return NGX_ERROR; + } - } else { - len = lua_objlen(L, -1); - } + return NGX_OK; - 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_HAVE_PCRE_JIT */ - } else { - lua_pushstring(L, name); /* big_tb cap key */ - lua_pushvalue(L, -2); /* big_tb cap key cap */ - lua_rawset(L, res_tb_idx); /* big_tb cap */ - lua_pop(L, 1); - } + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "no pcre jit support found") - errstr; + return NGX_ERROR; - dd("top 2: %d", lua_gettop(L)); - } +#endif /* LUA_HAVE_PCRE_JIT */ } @@ -2547,4 +586,5 @@ ngx_[% subsys %]_lua_ffi_max_regex_cache_size(void) #endif /* NGX_PCRE */ + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_regex.h.tt2 b/src/subsys/ngx_subsys_lua_regex.h.tt2 deleted file mode 100644 index 9b7fcd2..0000000 --- a/src/subsys/ngx_subsys_lua_regex.h.tt2 +++ /dev/null @@ -1,24 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef _NGX_[% SUBSYS %]_LUA_REGEX_H_INCLUDED_ -#define _NGX_[% SUBSYS %]_LUA_REGEX_H_INCLUDED_ - - -#include "ngx_[% subsys %]_lua_common.h" -#include "ngx_[% subsys %]_lua_script.h" - - -#if (NGX_PCRE) -void ngx_[% subsys %]_lua_inject_regex_api(lua_State *L); -ngx_int_t ngx_[% subsys %]_lua_ffi_set_jit_stack_size(int size, u_char *errstr, - size_t *errstr_size); -#endif - - -#endif /* _NGX_[% SUBSYS %]_LUA_REGEX_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_semaphore.c.tt2 b/src/subsys/ngx_subsys_lua_semaphore.c.tt2 index 523d4db..759c5e6 100644 --- a/src/subsys/ngx_subsys_lua_semaphore.c.tt2 +++ b/src/subsys/ngx_subsys_lua_semaphore.c.tt2 @@ -7,11 +7,6 @@ */ -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] - - #ifndef DDEBUG #define DDEBUG 0 #endif @@ -88,6 +83,8 @@ ngx_[% subsys %]_lua_alloc_sema(void) lmcf = ngx_[% subsys %]_cycle_get_module_main_conf(ngx_cycle, ngx_[% subsys %]_lua_module); + ngx_[% subsys %]_lua_assert(lmcf != NULL); + mm = lmcf->sema_mm; if (!ngx_queue_empty(&mm->free_queue)) { @@ -174,6 +171,8 @@ ngx_[% subsys %]_lua_sema_mm_cleanup(void *data) sem = ngx_queue_data(q, ngx_[% subsys %]_lua_sema_t, chain); block = sem->block; + ngx_[% subsys %]_lua_assert(block != NULL); + if (block->used == 0) { iter = (ngx_[% subsys %]_lua_sema_t *) (block + 1); @@ -367,7 +366,7 @@ ngx_[% subsys %]_lua_ffi_sema_wait([% req_type %] *r, "[% subsys %] lua semaphore wait: %p, timeout: %d, " "resources: %d, event posted: %d", sem, wait_ms, sem->resource_count, -#if (nginx_version >= 1007005) +#if defined(nginx_version) && nginx_version >= 1007005 (int) sem->sem_event.posted #else sem->sem_event.prev ? 1 : 0 @@ -591,8 +590,4 @@ ngx_[% subsys %]_lua_ffi_sema_gc(ngx_[% subsys %]_lua_sema_t *sem) } -[% IF http_subsys %] -#endif /* NGX_LUA_NO_FFI_API */ -[% END %] - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_semaphore.h.tt2 b/src/subsys/ngx_subsys_lua_semaphore.h.tt2 index d261250..a96f4f3 100644 --- a/src/subsys/ngx_subsys_lua_semaphore.h.tt2 +++ b/src/subsys/ngx_subsys_lua_semaphore.h.tt2 @@ -41,15 +41,9 @@ typedef struct ngx_[% subsys %]_lua_sema_s { } ngx_[% subsys %]_lua_sema_t; -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] void ngx_[% subsys %]_lua_sema_mm_cleanup(void *data); ngx_int_t ngx_[% subsys %]_lua_sema_mm_init(ngx_conf_t *cf, ngx_[% subsys %]_lua_main_conf_t *lmcf); -[% IF http_subsys %] -#endif -[% END %] #endif /* _NGX_[% SUBSYS %]_LUA_SEMAPHORE_H_INCLUDED_ */ diff --git a/src/subsys/ngx_subsys_lua_shdict.c.tt2 b/src/subsys/ngx_subsys_lua_shdict.c.tt2 index 883081b..5d55980 100644 --- a/src/subsys/ngx_subsys_lua_shdict.c.tt2 +++ b/src/subsys/ngx_subsys_lua_shdict.c.tt2 @@ -15,23 +15,11 @@ #include "ngx_[% subsys %]_lua_api.h" -static int ngx_[% subsys %]_lua_shdict_set(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_safe_set(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_get(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_get_stale(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_get_helper(lua_State *L, int get_stale); static int ngx_[% subsys %]_lua_shdict_expire(ngx_[% subsys %]_lua_shdict_ctx_t *ctx, ngx_uint_t n); static ngx_int_t ngx_[% subsys %]_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, u_char *kdata, size_t klen, ngx_[% subsys %]_lua_shdict_node_t **sdp); -static int ngx_[% subsys %]_lua_shdict_set_helper(lua_State *L, int flags); -static int ngx_[% subsys %]_lua_shdict_add(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_safe_add(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_replace(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_incr(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_delete(lua_State *L); -static int ngx_[% subsys %]_lua_shdict_flush_all(lua_State *L); static int ngx_[% subsys %]_lua_shdict_flush_expired(lua_State *L); static int ngx_[% subsys %]_lua_shdict_get_keys(lua_State *L); static int ngx_[% subsys %]_lua_shdict_lpush(lua_State *L); @@ -129,9 +117,7 @@ ngx_[% subsys %]_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 return NGX_OK; } @@ -338,34 +324,7 @@ ngx_[% subsys %]_lua_inject_shdict_api(ngx_[% subsys %]_lua_main_conf_t *lmcf, l lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); /* ngx.shared */ - lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_get); - lua_setfield(L, -2, "get"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_get_stale); - lua_setfield(L, -2, "get_stale"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_set); - lua_setfield(L, -2, "set"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_safe_set); - lua_setfield(L, -2, "safe_set"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_add); - lua_setfield(L, -2, "add"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_safe_add); - lua_setfield(L, -2, "safe_add"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_replace); - lua_setfield(L, -2, "replace"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_incr); - lua_setfield(L, -2, "incr"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_delete); - lua_setfield(L, -2, "delete"); + lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_lpush); lua_setfield(L, -2, "lpush"); @@ -382,9 +341,6 @@ ngx_[% subsys %]_lua_inject_shdict_api(ngx_[% subsys %]_lua_main_conf_t *lmcf, l lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_llen); lua_setfield(L, -2, "llen"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_flush_all); - lua_setfield(L, -2, "flush_all"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_shdict_flush_expired); lua_setfield(L, -2, "flush_expired"); @@ -423,20 +379,6 @@ ngx_[% subsys %]_lua_inject_shdict_api(ngx_[% subsys %]_lua_main_conf_t *lmcf, l } -static int -ngx_[% subsys %]_lua_shdict_get(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_get_helper(L, 0 /* stale */); -} - - -static int -ngx_[% subsys %]_lua_shdict_get_stale(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_get_helper(L, 1 /* stale */); -} - - static ngx_inline ngx_shm_zone_t * ngx_[% subsys %]_lua_shdict_get_zone(lua_State *L, int index) { @@ -456,1072 +398,202 @@ ngx_[% subsys %]_lua_shdict_get_zone(lua_State *L, int index) } -static int -ngx_[% subsys %]_lua_shdict_get_helper(lua_State *L, int get_stale) -{ - int n; - ngx_str_t name; - ngx_str_t key; - uint32_t hash; - ngx_int_t rc; - ngx_str_t value; - int value_type; - double num; - u_char c; - ngx_shm_zone_t *zone; - uint32_t user_flags = 0; - - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - ngx_[% subsys %]_lua_shdict_node_t *sd; - - n = lua_gettop(L); - - if (n != 2) { - return luaL_error(L, "expecting exactly two arguments, " - "but only seen %d", n); - } - - if (lua_type(L, 1) != LUA_TTABLE) { - return luaL_error(L, "bad \"zone\" argument"); - } - - zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); - if (zone == NULL) { - return luaL_error(L, "bad \"zone\" argument"); - } - - ctx = zone->data; - name = ctx->name; - - if (lua_isnil(L, 2)) { - lua_pushnil(L); - lua_pushliteral(L, "nil key"); - return 2; - } - - key.data = (u_char *) luaL_checklstring(L, 2, &key.len); - - if (key.len == 0) { - lua_pushnil(L); - lua_pushliteral(L, "empty key"); - return 2; - } - - if (key.len > 65535) { - lua_pushnil(L); - lua_pushliteral(L, "key too long"); - return 2; - } - - hash = ngx_crc32_short(key.data, key.len); - -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "fetching key \"%V\" in shared dict \"%V\"", &key, &name); -#endif /* NGX_DEBUG */ - - ngx_shmtx_lock(&ctx->shpool->mutex); - -#if 1 - if (!get_stale) { - ngx_[% subsys %]_lua_shdict_expire(ctx, 1); - } -#endif - - rc = ngx_[% subsys %]_lua_shdict_lookup(zone, hash, key.data, 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); - lua_pushnil(L); - return 1; - } - - /* 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; - - switch (value_type) { - - case SHDICT_TSTRING: - - lua_pushlstring(L, (char *) value.data, value.len); - break; - - case SHDICT_TNUMBER: - - if (value.len != sizeof(double)) { - - 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); - } - - ngx_memcpy(&num, value.data, sizeof(double)); - - lua_pushnumber(L, num); - break; - - case SHDICT_TBOOLEAN: - - if (value.len != sizeof(u_char)) { - - 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); - } - - c = *value.data; - - lua_pushboolean(L, c ? 1 : 0); - break; - - case SHDICT_TLIST: - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushnil(L); - lua_pushliteral(L, "value is a list"); - return 2; - - default: - - 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); - } - - user_flags = sd->user_flags; - - 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; - } - - return 1; -} - - -static int -ngx_[% subsys %]_lua_shdict_delete(lua_State *L) -{ - int n; - - n = lua_gettop(L); - - if (n != 2) { - return luaL_error(L, "expecting 2 arguments, " - "but only seen %d", n); - } - - lua_pushnil(L); - - return ngx_[% subsys %]_lua_shdict_set_helper(L, 0); -} - - -static int -ngx_[% subsys %]_lua_shdict_flush_all(lua_State *L) -{ - ngx_queue_t *q; - int n; - ngx_shm_zone_t *zone; - - ngx_[% subsys %]_lua_shdict_node_t *sd; - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - - n = lua_gettop(L); - - if (n != 1) { - return luaL_error(L, "expecting 1 argument, but seen %d", n); - } - - luaL_checktype(L, 1, LUA_TTABLE); - - zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); - if (zone == NULL) { - return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); - } - - ctx = zone->data; - - ngx_shmtx_lock(&ctx->shpool->mutex); - - for (q = ngx_queue_head(&ctx->sh->lru_queue); - q != ngx_queue_sentinel(&ctx->sh->lru_queue); - q = ngx_queue_next(q)) - { - sd = ngx_queue_data(q, ngx_[% subsys %]_lua_shdict_node_t, queue); - sd->expires = 1; - } - - ngx_[% subsys %]_lua_shdict_expire(ctx, 0); - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - return 0; -} - - -static int -ngx_[% subsys %]_lua_shdict_flush_expired(lua_State *L) -{ - ngx_queue_t *q, *prev, *list_queue, *lq; - ngx_shm_zone_t *zone; - ngx_time_t *tp; - int freed = 0; - int attempts = 0; - ngx_rbtree_node_t *node; - uint64_t now; - int n; - - ngx_[% subsys %]_lua_shdict_node_t *sd; - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - ngx_[% subsys %]_lua_shdict_list_node_t *lnode; - - 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_TTABLE); - - zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); - if (zone == NULL) { - return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); - } - - if (n == 2) { - attempts = luaL_checkint(L, 2); - } - - ctx = zone->data; - - ngx_shmtx_lock(&ctx->shpool->mutex); - - if (ngx_queue_empty(&ctx->sh->lru_queue)) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - lua_pushnumber(L, 0); - return 1; - } - - tp = ngx_timeofday(); - - now = (uint64_t) tp->sec * 1000 + tp->msec; - - q = ngx_queue_last(&ctx->sh->lru_queue); - - while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { - prev = ngx_queue_prev(q); - - sd = ngx_queue_data(q, ngx_[% subsys %]_lua_shdict_node_t, queue); - - if (sd->expires != 0 && sd->expires <= now) { - - if (sd->value_type == SHDICT_TLIST) { - list_queue = ngx_[% subsys %]_lua_shdict_get_list_head(sd, - sd->key_len); - - for (lq = ngx_queue_head(list_queue); - lq != ngx_queue_sentinel(list_queue); - lq = ngx_queue_next(lq)) - { - lnode = ngx_queue_data(lq, - ngx_[% subsys %]_lua_shdict_list_node_t, - queue); - - ngx_slab_free_locked(ctx->shpool, lnode); - } - } - - ngx_queue_remove(q); - - node = (ngx_rbtree_node_t *) - ((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) { - break; - } - } - - q = prev; - } - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushnumber(L, freed); - return 1; -} - - -/* - * This trades CPU for memory. This is potentially slow. O(2n) - */ - -static int -ngx_[% subsys %]_lua_shdict_get_keys(lua_State *L) -{ - ngx_queue_t *q, *prev; - ngx_shm_zone_t *zone; - ngx_time_t *tp; - int total = 0; - int attempts = 1024; - uint64_t now; - int n; - - ngx_[% subsys %]_lua_shdict_node_t *sd; - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - - 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_TTABLE); - - zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); - if (zone == NULL) { - return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); - } - - if (n == 2) { - attempts = luaL_checkint(L, 2); - } - - ctx = zone->data; - - ngx_shmtx_lock(&ctx->shpool->mutex); - - if (ngx_queue_empty(&ctx->sh->lru_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->lru_queue); - - while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { - prev = ngx_queue_prev(q); - - sd = ngx_queue_data(q, ngx_[% subsys %]_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->lru_queue); - - while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { - prev = ngx_queue_prev(q); - - sd = ngx_queue_data(q, ngx_[% subsys %]_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_[% subsys %]_lua_shdict_add(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_set_helper(L, NGX_[% SUBSYS %]_LUA_SHDICT_ADD); -} - - -static int -ngx_[% subsys %]_lua_shdict_safe_add(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_set_helper(L, - NGX_[% SUBSYS %]_LUA_SHDICT_ADD - |NGX_[% SUBSYS %]_LUA_SHDICT_SAFE_STORE); -} - - -static int -ngx_[% subsys %]_lua_shdict_replace(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_set_helper(L, NGX_[% SUBSYS %]_LUA_SHDICT_REPLACE); -} - - -static int -ngx_[% subsys %]_lua_shdict_set(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_set_helper(L, 0); -} - - -static int -ngx_[% subsys %]_lua_shdict_safe_set(lua_State *L) -{ - return ngx_[% subsys %]_lua_shdict_set_helper(L, - NGX_[% SUBSYS %]_LUA_SHDICT_SAFE_STORE); -} - - -static int -ngx_[% subsys %]_lua_shdict_set_helper(lua_State *L, int flags) -{ - int i, n; - ngx_str_t key; - uint32_t hash; - ngx_int_t rc; - ngx_str_t value; - int value_type; - double num; - u_char c; - lua_Number exptime = 0; - u_char *p; - ngx_rbtree_node_t *node; - ngx_time_t *tp; - ngx_shm_zone_t *zone; - int forcible = 0; - /* indicates whether to foricibly override other - * valid entries */ - int32_t user_flags = 0; - ngx_queue_t *queue, *q; - - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - ngx_[% subsys %]_lua_shdict_node_t *sd; - - n = lua_gettop(L); - - if (n != 3 && n != 4 && n != 5) { - return luaL_error(L, "expecting 3, 4 or 5 arguments, " - "but only seen %d", n); - } - - if (lua_type(L, 1) != LUA_TTABLE) { - return luaL_error(L, "bad \"zone\" argument"); - } - - zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); - if (zone == NULL) { - return luaL_error(L, "bad \"zone\" argument"); - } - - ctx = zone->data; - - if (lua_isnil(L, 2)) { - lua_pushnil(L); - lua_pushliteral(L, "nil key"); - return 2; - } - - key.data = (u_char *) luaL_checklstring(L, 2, &key.len); - - if (key.len == 0) { - lua_pushnil(L); - lua_pushliteral(L, "empty key"); - return 2; - } - - if (key.len > 65535) { - lua_pushnil(L); - lua_pushliteral(L, "key too long"); - return 2; - } - - hash = ngx_crc32_short(key.data, key.len); - - value_type = lua_type(L, 3); - - switch (value_type) { - - case SHDICT_TSTRING: - value.data = (u_char *) lua_tolstring(L, 3, &value.len); - break; - - case SHDICT_TNUMBER: - value.len = sizeof(double); - num = lua_tonumber(L, 3); - value.data = (u_char *) # - break; - - case SHDICT_TBOOLEAN: - value.len = sizeof(u_char); - c = lua_toboolean(L, 3) ? 1 : 0; - value.data = &c; - break; - - case LUA_TNIL: - if (flags & (NGX_[% SUBSYS %]_LUA_SHDICT_ADD|NGX_[% SUBSYS %]_LUA_SHDICT_REPLACE)) { - lua_pushnil(L); - lua_pushliteral(L, "attempt to add or replace nil values"); - return 2; - } - - ngx_str_null(&value); - break; - - default: - lua_pushnil(L); - lua_pushliteral(L, "bad value type"); - return 2; - } - - if (n >= 4) { - exptime = luaL_checknumber(L, 4); - if (exptime < 0) { - return luaL_error(L, "bad \"exptime\" argument"); - } - } - - if (n == 5) { - user_flags = (uint32_t) luaL_checkinteger(L, 5); - } - - ngx_shmtx_lock(&ctx->shpool->mutex); - -#if 1 - ngx_[% subsys %]_lua_shdict_expire(ctx, 1); -#endif - - rc = ngx_[% subsys %]_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); - - dd("shdict lookup returned %d", (int) rc); - - if (flags & NGX_[% SUBSYS %]_LUA_SHDICT_REPLACE) { - - if (rc == NGX_DECLINED || rc == NGX_DONE) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 0); - lua_pushliteral(L, "not found"); - lua_pushboolean(L, forcible); - return 3; - } - - /* rc == NGX_OK */ - - goto replace; - } - - if (flags & NGX_[% SUBSYS %]_LUA_SHDICT_ADD) { - - if (rc == NGX_OK) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 0); - lua_pushliteral(L, "exists"); - lua_pushboolean(L, forcible); - return 3; - } - - if (rc == NGX_DONE) { - /* exists but expired */ - - dd("go to replace"); - goto replace; - } - - /* rc == NGX_DECLINED */ - - dd("go to insert"); - goto insert; - } - - if (rc == NGX_OK || rc == NGX_DONE) { - - if (value_type == LUA_TNIL) { - goto remove; - } - -replace: - - if (value.data - && value.len == (size_t) sd->value_len - && sd->value_type != SHDICT_TLIST) - { - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict set: found old entry and value " - "size matched, reusing it"); - - ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); - - sd->key_len = (u_short) key.len; - - if (exptime > 0) { - tp = ngx_timeofday(); - sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + (uint64_t) (exptime * 1000); - - } else { - sd->expires = 0; - } - - sd->user_flags = user_flags; - - sd->value_len = (uint32_t) value.len; - - dd("setting value type to %d", 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); - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 1); - lua_pushnil(L); - lua_pushboolean(L, forcible); - return 3; - } - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict set: found old entry but value size " - "NOT matched, removing it first"); - -remove: - - if (sd->value_type == SHDICT_TLIST) { - queue = ngx_[% subsys %]_lua_shdict_get_list_head(sd, key.len); - - for (q = ngx_queue_head(queue); - q != ngx_queue_sentinel(queue); - q = ngx_queue_next(q)) - { - p = (u_char *) ngx_queue_data(q, - ngx_[% subsys %]_lua_shdict_list_node_t, - queue); - - ngx_slab_free_locked(ctx->shpool, p); - } - } - - ngx_queue_remove(&sd->queue); - - node = (ngx_rbtree_node_t *) - ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); - - ngx_rbtree_delete(&ctx->sh->rbtree, node); - - ngx_slab_free_locked(ctx->shpool, node); - - } - -insert: - - /* rc == NGX_DECLINED or value size unmatch */ - - if (value.data == NULL) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 1); - lua_pushnil(L); - lua_pushboolean(L, 0); - return 3; - } - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict set: creating a new entry"); - - n = offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_[% subsys %]_lua_shdict_node_t, data) - + key.len - + value.len; - - dd("overhead = %d", (int) (offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_[% subsys %]_lua_shdict_node_t, data))); - - node = ngx_slab_alloc_locked(ctx->shpool, n); - - if (node == NULL) { - - if (flags & NGX_[% SUBSYS %]_LUA_SHDICT_SAFE_STORE) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 0); - lua_pushliteral(L, "no memory"); - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict set: overriding non-expired items " - "due to memory shortage for entry \"%V\"", &key); - - for (i = 0; i < 30; i++) { - if (ngx_[% subsys %]_lua_shdict_expire(ctx, 0) == 0) { - break; - } - - forcible = 1; - - node = ngx_slab_alloc_locked(ctx->shpool, n); - if (node != NULL) { - goto allocated; - } - } - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 0); - lua_pushliteral(L, "no memory"); - lua_pushboolean(L, forcible); - return 3; - } - -allocated: - - sd = (ngx_[% subsys %]_lua_shdict_node_t *) &node->color; - - node->key = hash; - sd->key_len = (u_short) key.len; - - if (exptime > 0) { - tp = ngx_timeofday(); - sd->expires = (uint64_t) tp->sec * 1000 + tp->msec - + (uint64_t) (exptime * 1000); - - } else { - sd->expires = 0; - } - - sd->user_flags = user_flags; - - sd->value_len = (uint32_t) value.len; - - dd("setting value type to %d", 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); - - ngx_rbtree_insert(&ctx->sh->rbtree, node); - - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); - - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 1); - lua_pushnil(L); - lua_pushboolean(L, forcible); - return 3; -} - - -static int -ngx_[% subsys %]_lua_shdict_incr(lua_State *L) -{ - int i, n; - ngx_str_t key; - uint32_t hash; - ngx_int_t rc; - double num; - double init = 0; - u_char *p; - ngx_shm_zone_t *zone; - double value; - ngx_rbtree_node_t *node; - /* indicates whether to foricibly override other - * valid entries */ - int forcible = 0; - ngx_queue_t *queue, *q; - - ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - ngx_[% subsys %]_lua_shdict_node_t *sd; +static int +ngx_[% subsys %]_lua_shdict_flush_expired(lua_State *L) +{ + ngx_queue_t *q, *prev, *list_queue, *lq; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + int freed = 0; + int attempts = 0; + ngx_rbtree_node_t *node; + uint64_t now; + int n; + + ngx_[% subsys %]_lua_shdict_node_t *sd; + ngx_[% subsys %]_lua_shdict_ctx_t *ctx; + ngx_[% subsys %]_lua_shdict_list_node_t *lnode; n = lua_gettop(L); - if (n != 3 && n != 4) { - return luaL_error(L, "expecting 3 or 4 arguments, but only seen %d", n); + if (n != 1 && n != 2) { + return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n); } - if (lua_type(L, 1) != LUA_TTABLE) { - return luaL_error(L, "bad \"zone\" argument"); - } + luaL_checktype(L, 1, LUA_TTABLE); zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } - ctx = zone->data; - - if (lua_isnil(L, 2)) { - lua_pushnil(L); - lua_pushliteral(L, "nil key"); - return 2; - } - - key.data = (u_char *) luaL_checklstring(L, 2, &key.len); - - if (key.len == 0) { - lua_pushnil(L); - lua_pushliteral(L, "empty key"); - return 2; - } - - if (key.len > 65535) { - lua_pushnil(L); - lua_pushliteral(L, "key too long"); - return 2; + if (n == 2) { + attempts = luaL_checkint(L, 2); } - hash = ngx_crc32_short(key.data, key.len); + ctx = zone->data; - value = luaL_checknumber(L, 3); + ngx_shmtx_lock(&ctx->shpool->mutex); - if (n == 4) { - init = luaL_checknumber(L, 4); + if (ngx_queue_empty(&ctx->sh->lru_queue)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_pushnumber(L, 0); + return 1; } - dd("looking up key %.*s in shared dict %.*s", (int) key.len, key.data, - (int) ctx->name.len, ctx->name.data); - - ngx_shmtx_lock(&ctx->shpool->mutex); + tp = ngx_timeofday(); -#if 1 - ngx_[% subsys %]_lua_shdict_expire(ctx, 1); -#endif + now = (uint64_t) tp->sec * 1000 + tp->msec; - rc = ngx_[% subsys %]_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + q = ngx_queue_last(&ctx->sh->lru_queue); - dd("shdict lookup returned %d", (int) rc); + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); - if (rc == NGX_DECLINED || rc == NGX_DONE) { + sd = ngx_queue_data(q, ngx_[% subsys %]_lua_shdict_node_t, queue); - if (n == 3) { - ngx_shmtx_unlock(&ctx->shpool->mutex); + if (sd->expires != 0 && sd->expires <= now) { - lua_pushnil(L); - lua_pushliteral(L, "not found"); - return 2; - } + if (sd->value_type == SHDICT_TLIST) { + list_queue = ngx_[% subsys %]_lua_shdict_get_list_head(sd, + sd->key_len); - /* add value */ - num = value + init; + for (lq = ngx_queue_head(list_queue); + lq != ngx_queue_sentinel(list_queue); + lq = ngx_queue_next(lq)) + { + lnode = ngx_queue_data(lq, + ngx_[% subsys %]_lua_shdict_list_node_t, + queue); - if (rc == NGX_DONE) { + ngx_slab_free_locked(ctx->shpool, lnode); + } + } - /* found an expired item */ + ngx_queue_remove(q); - if ((size_t) sd->value_len == sizeof(double) - && sd->value_type != SHDICT_TLIST) - { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict incr: found old entry and " - "value size matched, reusing it"); + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); - ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + ngx_rbtree_delete(&ctx->sh->rbtree, node); + ngx_slab_free_locked(ctx->shpool, node); + freed++; - dd("go to setvalue"); - goto setvalue; + if (attempts && freed == attempts) { + break; } - - dd("go to remove"); - goto remove; } - dd("go to insert"); - goto insert; - } - - /* rc == NGX_OK */ - - if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushnil(L); - lua_pushliteral(L, "not a number"); - return 2; + q = prev; } - ngx_queue_remove(&sd->queue); - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); - - dd("setting value type to %d", (int) sd->value_type); - - p = sd->data + key.len; + ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_memcpy(&num, p, sizeof(double)); - num += value; + lua_pushnumber(L, freed); + return 1; +} - ngx_memcpy(p, (double *) &num, sizeof(double)); - ngx_shmtx_unlock(&ctx->shpool->mutex); +/* + * This trades CPU for memory. This is potentially slow. O(2n) + */ - lua_pushnumber(L, num); - lua_pushnil(L); - return 2; +static int +ngx_[% subsys %]_lua_shdict_get_keys(lua_State *L) +{ + ngx_queue_t *q, *prev; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + int total = 0; + int attempts = 1024; + uint64_t now; + int n; -remove: + ngx_[% subsys %]_lua_shdict_node_t *sd; + ngx_[% subsys %]_lua_shdict_ctx_t *ctx; - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict incr: found old entry but value size " - "NOT matched, removing it first"); + n = lua_gettop(L); - if (sd->value_type == SHDICT_TLIST) { - queue = ngx_[% subsys %]_lua_shdict_get_list_head(sd, key.len); + if (n != 1 && n != 2) { + return luaL_error(L, "expecting 1 or 2 argument(s), " + "but saw %d", n); + } - for (q = ngx_queue_head(queue); - q != ngx_queue_sentinel(queue); - q = ngx_queue_next(q)) - { - p = (u_char *) ngx_queue_data(q, - ngx_[% subsys %]_lua_shdict_list_node_t, - queue); + luaL_checktype(L, 1, LUA_TTABLE); - ngx_slab_free_locked(ctx->shpool, p); - } + zone = ngx_[% subsys %]_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } - ngx_queue_remove(&sd->queue); + if (n == 2) { + attempts = luaL_checkint(L, 2); + } - node = (ngx_rbtree_node_t *) - ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + ctx = zone->data; - ngx_rbtree_delete(&ctx->sh->rbtree, node); + ngx_shmtx_lock(&ctx->shpool->mutex); - ngx_slab_free_locked(ctx->shpool, node); + if (ngx_queue_empty(&ctx->sh->lru_queue)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_createtable(L, 0, 0); + return 1; + } -insert: + tp = ngx_timeofday(); - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict incr: creating a new entry"); + now = (uint64_t) tp->sec * 1000 + tp->msec; - n = offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_[% subsys %]_lua_shdict_node_t, data) - + key.len - + sizeof(double); + /* first run through: get total number of elements we need to allocate */ - node = ngx_slab_alloc_locked(ctx->shpool, n); + q = ngx_queue_last(&ctx->sh->lru_queue); - if (node == NULL) { + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], ctx->log, 0, - "lua shared dict incr: overriding non-expired items " - "due to memory shortage for entry \"%V\"", &key); + sd = ngx_queue_data(q, ngx_[% subsys %]_lua_shdict_node_t, queue); - for (i = 0; i < 30; i++) { - if (ngx_[% subsys %]_lua_shdict_expire(ctx, 0) == 0) { + if (sd->expires == 0 || sd->expires > now) { + total++; + if (attempts && total == attempts) { break; } - - forcible = 1; - - node = ngx_slab_alloc_locked(ctx->shpool, n); - if (node != NULL) { - goto allocated; - } } - ngx_shmtx_unlock(&ctx->shpool->mutex); - - lua_pushboolean(L, 0); - lua_pushliteral(L, "no memory"); - lua_pushboolean(L, forcible); - return 3; + q = prev; } -allocated: - - sd = (ngx_[% subsys %]_lua_shdict_node_t *) &node->color; - - node->key = hash; - - sd->key_len = (u_short) key.len; - - sd->value_len = (uint32_t) sizeof(double); - - ngx_rbtree_insert(&ctx->sh->rbtree, node); - - ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + lua_createtable(L, total, 0); -setvalue: + /* second run through: add keys to table */ - sd->user_flags = 0; + total = 0; + q = ngx_queue_last(&ctx->sh->lru_queue); - sd->expires = 0; + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); - dd("setting value type to %d", LUA_TNUMBER); + sd = ngx_queue_data(q, ngx_[% subsys %]_lua_shdict_node_t, queue); - sd->value_type = (uint8_t) LUA_TNUMBER; + 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; + } + } - p = ngx_copy(sd->data, key.data, key.len); - ngx_memcpy(p, (double *) &num, sizeof(double)); + q = prev; + } ngx_shmtx_unlock(&ctx->shpool->mutex); - lua_pushnumber(L, num); - lua_pushnil(L); - lua_pushboolean(L, forcible); - return 3; + /* table is at top of stack */ + return 1; } +[% IF http_subsys %] ngx_int_t ngx_[% subsys %]_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, size_t key_len, ngx_[% subsys %]_lua_value_t *value) @@ -1624,6 +696,7 @@ ngx_[% subsys %]_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } +[% END %] static int @@ -3031,7 +2104,7 @@ ngx_[% subsys %]_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) } -# if nginx_version >= 1011007 +#if defined(nginx_version) && nginx_version >= 1011007 size_t ngx_[% subsys %]_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) { @@ -3047,7 +2120,7 @@ ngx_[% subsys %]_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) return bytes; } -# endif /* nginx_version >= 1011007 */ +#endif /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_socket_tcp.c.tt2 b/src/subsys/ngx_subsys_lua_socket_tcp.c.tt2 index dbb13a4..d60d038 100644 --- a/src/subsys/ngx_subsys_lua_socket_tcp.c.tt2 +++ b/src/subsys/ngx_subsys_lua_socket_tcp.c.tt2 @@ -11,6 +11,7 @@ #include "ngx_[% subsys %]_lua_socket_tcp.h" +#include "ngx_[% subsys %]_lua_input_filters.h" #include "ngx_[% subsys %]_lua_util.h" #include "ngx_[% subsys %]_lua_uthread.h" #include "ngx_[% subsys %]_lua_output.h" @@ -24,9 +25,9 @@ static int ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_sslhandshake(lua_State *L); #endif static int ngx_[% subsys %]_lua_socket_tcp_receive(lua_State *L); +static int ngx_[% subsys %]_lua_socket_tcp_receiveany(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_send(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_close(lua_State *L); -static int ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_setoption(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_settimeout(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_settimeouts(lua_State *L); @@ -47,8 +48,13 @@ static void ngx_[% subsys %]_lua_socket_tcp_finalize([% req_type %] *r, static void ngx_[% subsys %]_lua_socket_tcp_finalize_read_part( [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); static void ngx_[% subsys %]_lua_socket_tcp_finalize_write_part( +[% IF stream_subsys %] [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, int do_shutdown); + +[% ELSIF http_subsys %] + [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); +[% END %] static ngx_int_t ngx_[% subsys %]_lua_socket_send([% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_[% subsys %]_lua_socket_test_connect([% req_type %] *r, @@ -74,6 +80,8 @@ static int ngx_[% subsys %]_lua_socket_tcp_conn_retval_handler( lua_State *L); static void ngx_[% subsys %]_lua_socket_dummy_handler([% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); +static int ngx_[% subsys %]_lua_socket_tcp_receive_helper([% req_type %] *r, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, lua_State *L); static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_read([% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); static int ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler( @@ -96,6 +104,7 @@ static int ngx_[% subsys %]_lua_socket_write_error_retval_handler( static ngx_int_t ngx_[% subsys %]_lua_socket_read_all(void *data, ssize_t bytes); static ngx_int_t ngx_[% subsys %]_lua_socket_read_until(void *data, ssize_t bytes); static ngx_int_t ngx_[% subsys %]_lua_socket_read_chunk(void *data, ssize_t bytes); +static ngx_int_t ngx_[% subsys %]_lua_socket_read_any(void *data, ssize_t bytes); static int ngx_[% subsys %]_lua_socket_tcp_receiveuntil(lua_State *L); static int ngx_[% subsys %]_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_[% subsys %]_lua_socket_compile_pattern(u_char *data, size_t len, @@ -104,12 +113,30 @@ static int ngx_[% subsys %]_lua_socket_cleanup_compiled_pattern(lua_State *L); static void ngx_[% subsys %]_lua_req_socket_rev_handler([% req_type %] *r); static int ngx_[% subsys %]_lua_socket_tcp_getreusedtimes(lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L); +static void ngx_[% subsys %]_lua_socket_tcp_create_socket_pool(lua_State *L, + [% req_type %] *r, ngx_str_t key, ngx_int_t pool_size, + ngx_int_t backlog, ngx_[% subsys %]_lua_socket_pool_t **spool); static ngx_int_t ngx_[% subsys %]_lua_get_keepalive_peer([% req_type %] *r, - lua_State *L, int key_index, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); static void ngx_[% subsys %]_lua_socket_keepalive_dummy_handler(ngx_event_t *ev); +static int ngx_[% subsys %]_lua_socket_tcp_connect_helper(lua_State *L, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, [% req_type %] *r, + ngx_[% subsys %]_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, + in_port_t port, unsigned resuming); +static void ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_handler( + ngx_event_t *ev); +static int ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_retval_handler( + [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, + lua_State *L); +static void ngx_[% subsys %]_lua_socket_tcp_resume_conn_op( + ngx_[% subsys %]_lua_socket_pool_t *spool); +static void ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_cleanup(void *data); +static void ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev); static ngx_int_t ngx_[% subsys %]_lua_socket_keepalive_close_handler(ngx_event_t *ev); static void ngx_[% subsys %]_lua_socket_keepalive_rev_handler(ngx_event_t *ev); +static int ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_retval_handler( + [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, + lua_State *L); static int ngx_[% subsys %]_lua_socket_tcp_upstream_destroy(lua_State *L); static int ngx_[% subsys %]_lua_socket_downstream_destroy(lua_State *L); static ngx_int_t ngx_[% subsys %]_lua_socket_push_input_data( @@ -123,6 +150,8 @@ static ngx_int_t ngx_[% subsys %]_lua_socket_add_input_buffer( static ngx_int_t ngx_[% subsys %]_lua_socket_insert_buffer( [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, u_char *pat, size_t prefix); +static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_conn_op_resume( + [% req_type %] *r); static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_conn_resume( [% req_type %] *r); static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_read_resume( @@ -131,6 +160,7 @@ static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_write_resume( [% req_type %] *r); static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_resume_helper( [% req_type %] *r, int socket_op); +static void ngx_[% subsys %]_lua_tcp_queue_conn_op_cleanup(void *data); static void ngx_[% subsys %]_lua_tcp_resolve_cleanup(void *data); static void ngx_[% subsys %]_lua_coctx_cleanup(void *data); static void ngx_[% subsys %]_lua_socket_free_pool(ngx_log_t *log, @@ -155,6 +185,7 @@ static void ngx_[% subsys %]_lua_socket_tcp_close_connection(ngx_connection_t *c [% IF stream_subsys %] static int ngx_[% subsys %]_lua_socket_tcp_peek(lua_State *L); static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_peek_resume([% req_type %] *r); +static int ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L); [% END %] @@ -170,7 +201,8 @@ enum { enum { SOCKET_OP_CONNECT, SOCKET_OP_READ, - SOCKET_OP_WRITE + SOCKET_OP_WRITE, + SOCKET_OP_RESUME_CONN }; @@ -296,11 +328,11 @@ ngx_[% subsys %]_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{raw req socket object metatable */ lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( raw_req_socket_metatable_key)); - lua_createtable(L, 0 /* narr */, 7 /* nrec */); +[% IF http_subsys %] + lua_createtable(L, 0 /* narr */, 6 /* nrec */); -[% IF stream_subsys %] - lua_pushcfunction(L, ngx_stream_lua_socket_tcp_peek); - lua_setfield(L, -2, "peek"); +[% ELSIF stream_subsys %] + lua_createtable(L, 0 /* narr */, 8 /* nrec */); [% END %] lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_receive); @@ -319,6 +351,9 @@ ngx_[% subsys %]_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_setfield(L, -2, "settimeouts"); /* ngx socket mt */ [% IF stream_subsys %] + lua_pushcfunction(L, ngx_stream_lua_socket_tcp_peek); + lua_setfield(L, -2, "peek"); + lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_shutdown); lua_setfield(L, -2, "shutdown"); [% END %] @@ -332,7 +367,12 @@ ngx_[% subsys %]_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{tcp object metatable */ lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( tcp_socket_metatable_key)); - lua_createtable(L, 0 /* narr */, 12 /* nrec */); +[% IF http_subsys %] + lua_createtable(L, 0 /* narr */, 13 /* nrec */); + +[% ELSIF stream_subsys %] + lua_createtable(L, 0 /* narr */, 14 /* nrec */); +[% END %] lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_connect); lua_setfield(L, -2, "connect"); @@ -350,15 +390,15 @@ ngx_[% subsys %]_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_receiveuntil); lua_setfield(L, -2, "receiveuntil"); + lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_receiveany); + lua_setfield(L, -2, "receiveany"); + lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_send); lua_setfield(L, -2, "send"); lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_close); lua_setfield(L, -2, "close"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_shutdown); - lua_setfield(L, -2, "shutdown"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_setoption); lua_setfield(L, -2, "setoption"); @@ -374,6 +414,11 @@ ngx_[% subsys %]_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_setkeepalive); lua_setfield(L, -2, "setkeepalive"); +[% IF stream_subsys %] + lua_pushcfunction(L, ngx_[% subsys %]_lua_socket_tcp_shutdown); + lua_setfield(L, -2, "shutdown"); +[% END %] + lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_rawset(L, LUA_REGISTRYINDEX); @@ -474,14 +519,107 @@ ngx_[% subsys %]_lua_socket_tcp(lua_State *L) } +static void +ngx_[% subsys %]_lua_socket_tcp_create_socket_pool(lua_State *L, + [% req_type %] *r, ngx_str_t key, ngx_int_t pool_size, ngx_int_t backlog, + ngx_[% subsys %]_lua_socket_pool_t **spool) +{ + u_char *p; + size_t size, key_len; + ngx_int_t i; + + ngx_[% subsys %]_lua_socket_pool_t *sp; + ngx_[% subsys %]_lua_socket_pool_item_t *items; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket connection pool size: " + "%i, backlog: %i", + pool_size, backlog); + + key_len = ngx_align(key.len + 1, sizeof(void *)); + + size = sizeof(ngx_[% subsys %]_lua_socket_pool_t) - 1 + key_len + + sizeof(ngx_[% subsys %]_lua_socket_pool_item_t) * pool_size; + + /* before calling this function, the Lua stack is: + * -1 key + * -2 pools + */ + sp = lua_newuserdata(L, size); + if (sp == NULL) { + luaL_error(L, "no memory"); + return; + } + + lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( + pool_udata_metatable_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket keepalive create " + "connection pool for key \"%V\"", &key); + + /* a new socket pool with metatable is push to the stack, so now we have: + * -1 sp + * -2 key + * -3 pools + * + * it is time to set pools[key] to sp. + */ + lua_rawset(L, -3); + + /* clean up the stack for consistency's sake */ + lua_pop(L, 1); + + sp->backlog = backlog; + sp->size = pool_size; + sp->connections = 0; + sp->lua_vm = ngx_[% subsys %]_lua_get_lua_vm(r, NULL); + + ngx_queue_init(&sp->cache_connect_op); + ngx_queue_init(&sp->wait_connect_op); + ngx_queue_init(&sp->cache); + ngx_queue_init(&sp->free); + + p = ngx_copy(sp->key, key.data, key.len); + *p++ = '\0'; + + items = (ngx_[% subsys %]_lua_socket_pool_item_t *) (sp->key + key_len); + + dd("items: %p", items); + + ngx_[% subsys %]_lua_assert((void *) items + == ngx_align_ptr(items, sizeof(void *))); + + for (i = 0; i < pool_size; i++) { + ngx_queue_insert_head(&sp->free, &items[i].queue); + items[i].socket_pool = sp; + } + + *spool = sp; +} + + static int -ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) +ngx_[% subsys %]_lua_socket_tcp_connect_helper(lua_State *L, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, [% req_type %] *r, + ngx_[% subsys %]_lua_ctx_t *ctx, u_char *host_ref, size_t host_len, + in_port_t port, unsigned resuming) { - [% req_type %] *r; - ngx_[% subsys %]_lua_ctx_t *ctx; - ngx_str_t host; - int port; - ngx_resolver_ctx_t *rctx, temp; + int n; + int host_size; + int saved_top; + ngx_int_t rc; + ngx_str_t host; + ngx_str_t *conn_op_host; + ngx_url_t url; + ngx_queue_t *q; + ngx_resolver_ctx_t *rctx, temp; + + ngx_[% subsys %]_lua_co_ctx_t *coctx; + ngx_[% subsys %]_lua_socket_pool_t *spool; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; [% IF http_subsys %] ngx_http_core_loc_conf_t *clcf; @@ -490,21 +628,322 @@ ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) ngx_stream_core_srv_conf_t *clcf; [% END %] - int saved_top; + spool = u->socket_pool; + if (spool != NULL) { + rc = ngx_[% subsys %]_lua_get_keepalive_peer(r, u); + + if (rc == NGX_OK) { + lua_pushinteger(L, 1); + return 1; + } + + /* rc == NGX_DECLINED */ + + spool->connections++; + + /* check if backlog is enabled and + * don't queue resuming connection operation */ + if (spool->backlog >= 0 && !resuming) { + + dd("lua tcp socket %s connections %ld", + spool->key, spool->connections); + + if (spool->connections > spool->size + spool->backlog) { + spool->connections--; + lua_pushnil(L); + lua_pushliteral(L, "too many waiting connect operations"); + return 2; + } + + if (spool->connections > spool->size) { + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], u->peer.log, 0, + "[% log_prefix %]lua tcp socket queue connect " + "operation for connection pool \"%s\", " + "connections: %i", + spool->key, spool->connections); + + host_size = sizeof(u_char) * + (ngx_max(host_len, NGX_INET_ADDRSTRLEN) + 1); + + if (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_last(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data( + q, ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t, queue); + + conn_op_host = &conn_op_ctx->host; + if (host_len > conn_op_host->len + && host_len > NGX_INET_ADDRSTRLEN) + { + ngx_free(conn_op_host->data); + conn_op_host->data = ngx_alloc(host_size, + ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + } else { + conn_op_ctx = ngx_alloc( + sizeof(ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t), + ngx_cycle->log); + if (conn_op_ctx == NULL) { + goto no_memory_and_not_resuming; + } + + conn_op_host = &conn_op_ctx->host; + conn_op_host->data = ngx_alloc(host_size, ngx_cycle->log); + if (conn_op_host->data == NULL) { + ngx_free(conn_op_ctx); + goto no_memory_and_not_resuming; + } + } + + conn_op_ctx->cleanup = NULL; + + ngx_memcpy(conn_op_host->data, host_ref, host_len); + conn_op_host->data[host_len] = '\0'; + conn_op_host->len = host_len; + + conn_op_ctx->port = port; + + u->write_co_ctx = ctx->cur_co_ctx; + + conn_op_ctx->u = u; + ctx->cur_co_ctx->cleanup = + ngx_[% subsys %]_lua_tcp_queue_conn_op_cleanup; + ctx->cur_co_ctx->data = conn_op_ctx; + + ngx_memzero(&conn_op_ctx->event, sizeof(ngx_event_t)); + conn_op_ctx->event.handler = + ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_handler; + conn_op_ctx->event.data = conn_op_ctx; + conn_op_ctx->event.log = ngx_cycle->log; + + ngx_add_timer(&conn_op_ctx->event, u->connect_timeout); + + ngx_queue_insert_tail(&spool->wait_connect_op, + &conn_op_ctx->queue); + + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua tcp socket queued connect " + "operation for %d(ms), u: %p, ctx: %p", + u->connect_timeout, conn_op_ctx->u, conn_op_ctx); + + return lua_yield(L, 0); + } + } + + } /* end spool != NULL */ + + host.data = ngx_palloc(r->pool, host_len + 1); + if (host.data == NULL) { + return luaL_error(L, "no memory"); + } + + host.len = host_len; + + ngx_memcpy(host.data, host_ref, host_len); + host.data[host_len] = '\0'; + + ngx_memzero(&url, sizeof(ngx_url_t)); + url.url = host; + url.default_port = port; + url.no_resolve = 1; + + coctx = ctx->cur_co_ctx; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + lua_pushnil(L); + + if (url.err) { + lua_pushfstring(L, "failed to parse host name \"%s\": %s", + url.url.data, url.err); + + } else { + lua_pushfstring(L, "failed to parse host name \"%s\"", + url.url.data); + } + + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket connect timeout: %M", + u->connect_timeout); + + u->resolved = ngx_pcalloc(r->pool, + sizeof(ngx_[% subsys %]_upstream_resolved_t)); + if (u->resolved == NULL) { + if (resuming) { + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + goto failed; + } + + goto no_memory_and_not_resuming; + } + + if (url.addrs && url.addrs[0].sockaddr) { + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket network address given " + "directly"); + + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; + + } else { + u->resolved->host = host; + u->resolved->port = url.default_port; + } + + if (u->resolved->sockaddr) { + rc = ngx_[% subsys %]_lua_socket_resolve_retval_handler(r, u, L); + if (rc == NGX_AGAIN && !resuming) { + return lua_yield(L, 0); + } + + if (rc > 1) { + goto failed; + } + + return rc; + } + + clcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_core_module); + + temp.name = host; + rctx = ngx_resolve_start(clcf->resolver, &temp); + if (rctx == NULL) { + u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushliteral(L, "failed to start the resolver"); + goto failed; + } + + if (rctx == NGX_NO_RESOLVER) { + u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; + lua_pushnil(L); + lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); + goto failed; + } + + rctx->name = host; + rctx->handler = ngx_[% subsys %]_lua_socket_resolve_handler; + rctx->data = u; + rctx->timeout = clcf->resolver_timeout; + + u->resolved->ctx = rctx; + u->write_co_ctx = ctx->cur_co_ctx; + + ngx_[% subsys %]_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_[% subsys %]_lua_tcp_resolve_cleanup; + coctx->data = u; + + saved_top = lua_gettop(L); + + if (ngx_resolve_name(rctx) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket fail to run resolver " + "immediately"); + + u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; + + coctx->cleanup = NULL; + coctx->data = NULL; + + u->resolved->ctx = NULL; + lua_pushnil(L); + lua_pushfstring(L, "%s could not be resolved", host.data); + goto failed; + } + + if (u->conn_waiting) { + dd("resolved and already connecting"); + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + } + + n = lua_gettop(L) - saved_top; + if (n) { + dd("errors occurred during resolving or connecting" + "or already connected"); + + if (n > 1) { + goto failed; + } + + return n; + } + + /* still resolving */ + + u->conn_waiting = 1; + u->write_prepare_retvals = ngx_[% subsys %]_lua_socket_resolve_retval_handler; + + dd("setting data to %p", u); + + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; + } + + if (resuming) { + return NGX_AGAIN; + } + + return lua_yield(L, 0); + +failed: + + if (spool != NULL) { + spool->connections--; + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(spool); + } + + return 2; + +no_memory_and_not_resuming: + + if (spool != NULL) { + spool->connections--; + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(spool); + } + + return luaL_error(L, "no memory"); +} + + +static int +ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) +{ + [% req_type %] *r; + ngx_[% subsys %]_lua_ctx_t *ctx; + int port; int n; u_char *p; size_t len; - ngx_url_t url; - ngx_int_t rc; ngx_peer_connection_t *pc; int connect_timeout, send_timeout, read_timeout; unsigned custom_pool; int key_index; + ngx_int_t backlog; + ngx_int_t pool_size; + ngx_str_t key; const char *msg; ngx_[% subsys %]_lua_loc_conf_t *llcf; - ngx_[% subsys %]_lua_co_ctx_t *coctx; ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_socket_pool_t *spool; n = lua_gettop(L); if (n != 2 && n != 3 && n != 4) { @@ -540,13 +979,54 @@ ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) p = (u_char *) luaL_checklstring(L, 2, &len); + backlog = -1; key_index = 2; + pool_size = 0; custom_pool = 0; + llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); if (lua_type(L, n) == LUA_TTABLE) { /* found the last optional option table */ + lua_getfield(L, n, "pool_size"); + + if (lua_isnumber(L, -1)) { + pool_size = (ngx_int_t) lua_tointeger(L, -1); + + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); + } + + } else if (!lua_isnil(L, -1)) { + msg = lua_pushfstring(L, "bad \"pool_size\" option type: %s", + lua_typename(L, lua_type(L, -1))); + return luaL_argerror(L, n, msg); + } + + lua_pop(L, 1); + + lua_getfield(L, n, "backlog"); + + if (lua_isnumber(L, -1)) { + backlog = (ngx_int_t) lua_tointeger(L, -1); + + if (backlog < 0) { + msg = lua_pushfstring(L, "bad \"backlog\" option value: %i", + backlog); + return luaL_argerror(L, n, msg); + } + + /* use default value for pool size if only backlog specified */ + if (pool_size == 0) { + pool_size = llcf->pool_size; + } + } + + lua_pop(L, 1); + lua_getfield(L, n, "pool"); switch (lua_type(L, -1)) { @@ -658,12 +1138,8 @@ ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) ngx_memzero(u, sizeof(ngx_[% subsys %]_lua_socket_tcp_upstream_t)); - coctx = ctx->cur_co_ctx; - u->request = r; /* set the controlling request */ - llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); - u->conf = llcf; pc = &u->peer; @@ -704,165 +1180,29 @@ ngx_[% subsys %]_lua_socket_tcp_connect(lua_State *L) u->read_timeout = u->conf->read_timeout; } - rc = ngx_[% subsys %]_lua_get_keepalive_peer(r, L, key_index, u); - - if (rc == NGX_OK) { - lua_pushinteger(L, 1); - return 1; - } - - if (rc == NGX_ERROR) { - lua_pushnil(L); - lua_pushliteral(L, "error in get keepalive peer"); - return 2; - } - - /* rc == NGX_DECLINED */ - - /* TODO: we should avoid this in-pool allocation */ - - host.data = ngx_palloc(r->pool, len + 1); - if (host.data == NULL) { - return luaL_error(L, "no memory"); - } - - host.len = len; - - ngx_memcpy(host.data, p, len); - host.data[len] = '\0'; - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url.len = host.len; - url.url.data = host.data; - url.default_port = (in_port_t) port; - url.no_resolve = 1; - - if (ngx_parse_url(r->pool, &url) != NGX_OK) { - lua_pushnil(L); - - if (url.err) { - lua_pushfstring(L, "failed to parse host name \"%s\": %s", - host.data, url.err); - - } else { - lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); - } - - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua tcp socket connect timeout: %M", - u->connect_timeout); - - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_[% subsys %]_upstream_resolved_t)); - if (u->resolved == NULL) { - return luaL_error(L, "no memory"); - } - - if (url.addrs && url.addrs[0].sockaddr) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua tcp socket network address given directly"); - - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->naddrs = 1; - u->resolved->host = url.addrs[0].name; - - } else { - u->resolved->host = host; - u->resolved->port = (in_port_t) port; - } - - if (u->resolved->sockaddr) { - rc = ngx_[% subsys %]_lua_socket_resolve_retval_handler(r, u, L); - if (rc == NGX_AGAIN) { - return lua_yield(L, 0); - } - - return rc; - } - - clcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_core_module); - - temp.name = host; - rctx = ngx_resolve_start(clcf->resolver, &temp); - if (rctx == NULL) { - u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushliteral(L, "failed to start the resolver"); - return 2; - } - - if (rctx == NGX_NO_RESOLVER) { - u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; - lua_pushnil(L); - lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); - return 2; - } - - rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif - rctx->handler = ngx_[% subsys %]_lua_socket_resolve_handler; - rctx->data = u; - rctx->timeout = clcf->resolver_timeout; - - u->resolved->ctx = rctx; - u->write_co_ctx = ctx->cur_co_ctx; - - ngx_[% subsys %]_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_[% subsys %]_lua_tcp_resolve_cleanup; - coctx->data = u; - - saved_top = lua_gettop(L); - - if (ngx_resolve_name(rctx) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua tcp socket fail to run resolver " - "immediately"); - - u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_RESOLVER; - - coctx->cleanup = NULL; - coctx->data = NULL; - - u->resolved->ctx = NULL; - lua_pushnil(L); - lua_pushfstring(L, "%s could not be resolved", host.data); - - return 2; - } - - if (u->conn_waiting) { - dd("resolved and already connecting"); - return lua_yield(L, 0); - } - - n = lua_gettop(L) - saved_top; - if (n) { - dd("errors occurred during resolving or connecting" - "or already connected"); - return n; - } - - /* still resolving */ + lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( + socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); /* table */ + lua_pushvalue(L, key_index); /* key */ - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_[% subsys %]_lua_socket_resolve_retval_handler; + lua_rawget(L, -2); + spool = lua_touserdata(L, -1); + lua_pop(L, 1); - dd("setting data to %p", u); + if (spool != NULL) { + u->socket_pool = spool; - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; + } else if (pool_size > 0) { + lua_pushvalue(L, key_index); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); - } else { - r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; + ngx_[% subsys %]_lua_socket_tcp_create_socket_pool(L, r, key, pool_size, + backlog, &spool); + u->socket_pool = spool; } - return lua_yield(L, 0); + return ngx_[% subsys %]_lua_socket_tcp_connect_helper(L, u, r, ctx, p, + len, port, 0); } @@ -887,12 +1227,8 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_State *L; u_char *p; size_t len; -#if defined(nginx_version) && nginx_version >= 1005008 socklen_t socklen; struct sockaddr *sockaddr; -#else - struct sockaddr_in *sin; -#endif ngx_uint_t i; unsigned waiting; @@ -963,36 +1299,19 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) #if (NGX_DEBUG) { -# if defined(nginx_version) && nginx_version >= 1005008 - u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; -# else - in_addr_t addr; -# endif - ngx_uint_t i; - -# if defined(nginx_version) && nginx_version >= 1005008 - addr.data = text; - - for (i = 0; i < ctx->naddrs; i++) { - addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, - text, NGX_SOCKADDR_STRLEN, 0); + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + ngx_uint_t i; - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "name was resolved to %V", &addr); - } -# else - for (i = 0; i < ctx->naddrs; i++) { - dd("addr i: %d %p", (int) i, &ctx->addrs[i]); + addr.data = text; - addr = ntohl(ctx->addrs[i]); + for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); - ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], c->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); - } -# endif + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "name was resolved to %V", &addr); + } } #endif @@ -1007,7 +1326,6 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) dd("selected addr index: %d", (int) i); -#if defined(nginx_version) && nginx_version >= 1005008 socklen = ur->addrs[i].socklen; sockaddr = ngx_palloc(r->pool, socklen); @@ -1035,31 +1353,6 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); ur->sockaddr = sockaddr; ur->socklen = socklen; - -#else - /* for nginx older than 1.5.8 */ - - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - - p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in)); - if (p == NULL) { - goto nomem; - } - - sin = (struct sockaddr_in *) &p[len]; - ngx_memzero(sin, sizeof(struct sockaddr_in)); - - len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN); - len = ngx_sprintf(&p[len], ":%d", ur->port) - p; - - sin->sin_family = AF_INET; - sin->sin_port = htons(ur->port); - sin->sin_addr.s_addr = ur->addrs[i]; - - ur->sockaddr = (struct sockaddr *) sin; - ur->socklen = sizeof(struct sockaddr_in); -#endif - ur->host.data = p; ur->host.len = len; ur->naddrs = 1; @@ -1586,12 +1879,12 @@ new_ssl_name: c->ssl->handler = ngx_[% subsys %]_lua_ssl_handshake_handler; - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; - } else { - r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; - } + } else { + r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; + } return lua_yield(L, 0); } @@ -1794,7 +2087,12 @@ ngx_[% subsys %]_lua_socket_write_error_retval_handler([% req_type %] *r, u->write_co_ctx->cleanup = NULL; } +[% IF http_subsys %] + ngx_[% subsys %]_lua_socket_tcp_finalize_write_part(r, u); + +[% ELSIF stream_subsys %] ngx_[% subsys %]_lua_socket_tcp_finalize_write_part(r, u, 0); +[% END %] ft_type = u->ft_type; u->ft_type = 0; @@ -1835,11 +2133,7 @@ ngx_[% subsys %]_lua_socket_prepare_error_retvals([% req_type %] *r, } else { if (u->socket_errno) { -#if defined(nginx_version) && nginx_version >= 9000 p = ngx_strerror(u->socket_errno, errstr, sizeof(errstr)); -#else - p = ngx_strerror_r(u->socket_errno, errstr, sizeof(errstr)); -#endif /* for compatibility with LuaSocket */ ngx_strlow(errstr, errstr, p - errstr); lua_pushlstring(L, (char *) errstr, p - errstr); @@ -2043,14 +2337,169 @@ ngx_[% subsys %]_lua_socket_tcp_peek_resume([% req_type %] *r) [% END %] +static int +ngx_[% subsys %]_lua_socket_tcp_receive_helper([% req_type %] *r, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_ctx_t *lctx; + ngx_[% subsys %]_lua_co_ctx_t *coctx; + + u->input_filter_ctx = u; + + lctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + + if (u->bufs_in == NULL) { + u->bufs_in = + ngx_[% subsys %]_lua_chain_get_free_buf(r->connection->log, + r->pool, + &lctx->free_recv_bufs, + u->conf->buffer_size); + + if (u->bufs_in == NULL) { + return luaL_error(L, "no memory"); + } + + u->buf_in = u->bufs_in; + u->buffer = *u->buf_in->buf; + } + + dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket read timeout: %M", u->read_timeout); + + if (u->raw_downstream || u->body_downstream) { + r->read_event_handler = ngx_[% subsys %]_lua_req_socket_rev_handler; + } + + u->read_waiting = 0; + u->read_co_ctx = NULL; + + rc = ngx_[% subsys %]_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR) { + dd("read failed: %d", (int) u->ft_type); + rc = ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler(r, u, L); + dd("tcp receive retval returned: %d", (int) rc); + return rc; + } + + if (rc == NGX_OK) { + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket receive done in a single run"); + + return ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler(r, u, L); + } + + /* rc == NGX_AGAIN */ + + u->read_event_handler = ngx_[% subsys %]_lua_socket_read_handler; + + coctx = lctx->cur_co_ctx; + + ngx_[% subsys %]_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_[% subsys %]_lua_coctx_cleanup; + coctx->data = u; + + if (lctx->entered_content_phase) { + r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; + } + + u->read_co_ctx = coctx; + u->read_waiting = 1; + u->read_prepare_retvals = ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler; + + dd("setting data to %p, coctx:%p", u, coctx); + + if (u->raw_downstream || u->body_downstream) { + lctx->downstream = u; + } + + return lua_yield(L, 0); +} + + +static int +ngx_[% subsys %]_lua_socket_tcp_receiveany(lua_State *L) +{ + int n; + lua_Integer bytes; + [% req_type %] *r; + ngx_[% subsys %]_lua_loc_conf_t *llcf; + + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + + n = lua_gettop(L); + if (n != 2) { + return luaL_error(L, "expecting 2 arguments " + "(including the object), but got %d", n); + } + + r = ngx_[% subsys %]_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + lua_rawgeti(L, 1, SOCKET_CTX_INDEX); + u = lua_touserdata(L, -1); + + if (u == NULL || u->peer.connection == NULL || u->read_closed) { + + llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "attempt to receive data on a closed " + "socket: u:%p, c:%p, ft:%d eof:%d", + u, u ? u->peer.connection : NULL, + u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); + } + + lua_pushnil(L); + lua_pushliteral(L, "closed"); + return 2; + } + + if (u->request != r) { + return luaL_error(L, "bad request"); + } + + ngx_[% subsys %]_lua_socket_check_busy_connecting(r, u, L); + ngx_[% subsys %]_lua_socket_check_busy_reading(r, u, L); + + if (!lua_isnumber(L, 2)) { + return luaL_argerror(L, 2, "bad max argument"); + } + + bytes = lua_tointeger(L, 2); + if (bytes <= 0) { + return luaL_argerror(L, 2, "bad max argument"); + } + + u->input_filter = ngx_[% subsys %]_lua_socket_read_any; + u->rest = (size_t) bytes; + u->length = u->rest; + + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket calling receiveany() " + "method to read at most %uz bytes", u->rest); + + return ngx_[% subsys %]_lua_socket_tcp_receive_helper(r, u, L); +} + + static int ngx_[% subsys %]_lua_socket_tcp_receive(lua_State *L) { [% req_type %] *r; - ngx_int_t rc; - ngx_[% subsys %]_lua_ctx_t *ctx; ngx_[% subsys %]_lua_loc_conf_t *llcf; - ngx_[% subsys %]_lua_co_ctx_t *coctx; int n; ngx_str_t pat; lua_Integer bytes; @@ -2084,8 +2533,8 @@ ngx_[% subsys %]_lua_socket_tcp_receive(lua_State *L) if (llcf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "attempt to receive data on a closed socket: u:%p, " - "c:%p, ft:%d eof:%d", + "[% log_prefix %]attempt to receive data on a closed " + "socket: u:%p, c:%p, ft:%d eof:%d", u, u ? u->peer.connection : NULL, u ? (int) u->ft_type : 0, u ? (int) u->eof : 0); } @@ -2172,119 +2621,27 @@ ngx_[% subsys %]_lua_socket_tcp_receive(lua_State *L) u->rest = 0; } - u->input_filter_ctx = u; - - ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); - - if (u->bufs_in == NULL) { - u->bufs_in = - ngx_[% subsys %]_lua_chain_get_free_buf(r->connection->log, r->pool, - &ctx->free_recv_bufs, - u->conf->buffer_size); - - if (u->bufs_in == NULL) { - return luaL_error(L, "no memory"); - } - - u->buf_in = u->bufs_in; - u->buffer = *u->buf_in->buf; - } - - dd("tcp receive: buf_in: %p, bufs_in: %p", u->buf_in, u->bufs_in); - - if (u->raw_downstream || u->body_downstream) { - r->read_event_handler = ngx_[% subsys %]_lua_req_socket_rev_handler; - } - - u->read_waiting = 0; - u->read_co_ctx = NULL; - - rc = ngx_[% subsys %]_lua_socket_tcp_read(r, u); - - if (rc == NGX_ERROR) { - dd("read failed: %d", (int) u->ft_type); - rc = ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler(r, u, L); - dd("tcp receive retval returned: %d", (int) rc); - return rc; - } - - if (rc == NGX_OK) { - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua tcp socket receive done in a single run"); - - return ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler(r, u, L); - } - - /* rc == NGX_AGAIN */ - - u->read_event_handler = ngx_[% subsys %]_lua_socket_read_handler; - - coctx = ctx->cur_co_ctx; - - ngx_[% subsys %]_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_[% subsys %]_lua_coctx_cleanup; - coctx->data = u; - - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_[% subsys %]_lua_content_wev_handler; - - } else { - r->write_event_handler = ngx_[% req_subsys %]_core_run_phases; - } - - u->read_co_ctx = coctx; - u->read_waiting = 1; - u->read_prepare_retvals = ngx_[% subsys %]_lua_socket_tcp_receive_retval_handler; - - dd("setting data to %p, coctx:%p", u, coctx); - - if (u->raw_downstream || u->body_downstream) { - ctx->downstream = u; - } - - return lua_yield(L, 0); + return ngx_[% subsys %]_lua_socket_tcp_receive_helper(r, u, L); } static ngx_int_t ngx_[% subsys %]_lua_socket_read_chunk(void *data, ssize_t bytes) { - ngx_[% subsys %]_lua_socket_tcp_upstream_t *u = data; - - ngx_buf_t *b; -#if (NGX_DEBUG) - [% req_type %] *r; - - r = u->request; -#endif + ngx_int_t rc; + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u = data; - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, "[% log_prefix %]lua tcp socket read chunk %z", bytes); - if (bytes == 0) { + rc = ngx_[% subsys %]_lua_read_bytes(&u->buffer, u->buf_in, &u->rest, + bytes, u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; - - if (bytes >= (ssize_t) u->rest) { - - u->buf_in->buf->last += u->rest; - b->pos += u->rest; - u->rest = 0; - - return NGX_OK; - } - - /* bytes < u->rest */ - - u->buf_in->buf->last += bytes; - b->pos += bytes; - u->rest -= bytes; - - return NGX_AGAIN; + return rc; } @@ -2293,100 +2650,50 @@ ngx_[% subsys %]_lua_socket_read_all(void *data, ssize_t bytes) { ngx_[% subsys %]_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; -#if (NGX_DEBUG) - [% req_type %] *r; - - r = u->request; -#endif - - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, "[% log_prefix %]lua tcp socket read all"); - - if (bytes == 0) { - return NGX_OK; - } - - b = &u->buffer; - - u->buf_in->buf->last += bytes; - b->pos += bytes; - - return NGX_AGAIN; + return ngx_[% subsys %]_lua_read_all(&u->buffer, u->buf_in, bytes, + u->request->connection->log); } static ngx_int_t ngx_[% subsys %]_lua_socket_read_line(void *data, ssize_t bytes) { + ngx_int_t rc; ngx_[% subsys %]_lua_socket_tcp_upstream_t *u = data; - ngx_buf_t *b; - u_char *dst; - u_char c; -#if (NGX_DEBUG) - u_char *begin; -#endif - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, "[% log_prefix %]lua tcp socket read line"); - if (bytes == 0) { + rc = ngx_[% subsys %]_lua_read_line(&u->buffer, u->buf_in, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_CLOSED; return NGX_ERROR; } - b = &u->buffer; - -#if (NGX_DEBUG) - begin = b->pos; -#endif - - dd("already read: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); - - dd("data read: %.*s", (int) bytes, b->pos); - - dst = u->buf_in->buf->last; - - while (bytes--) { - - c = *b->pos++; - - switch (c) { - case '\n': - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, - "[% log_prefix %]lua tcp socket read the final line " - "part: \"%*s\"", b->pos - 1 - begin, begin); - - u->buf_in->buf->last = dst; + return rc; +} - dd("read a line: %p: %.*s", u->buf_in, - (int) (u->buf_in->buf->last - u->buf_in->buf->pos), - u->buf_in->buf->pos); - return NGX_OK; +static ngx_int_t +ngx_[% subsys %]_lua_socket_read_any(void *data, ssize_t bytes) +{ + ngx_int_t rc; + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u = data; - case '\r': - /* ignore it */ - break; + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, + "[% log_prefix %]lua tcp socket read any"); - default: - *dst++ = c; - break; - } + rc = ngx_[% subsys %]_lua_read_any(&u->buffer, u->buf_in, &u->rest, bytes, + u->request->connection->log); + if (rc == NGX_ERROR) { + u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_CLOSED; + return NGX_ERROR; } -#if (NGX_DEBUG) - ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, - "[% log_prefix %]lua tcp socket read partial line data: %*s", - dst - begin, begin); -#endif - - u->buf_in->buf->last = dst; - - return NGX_AGAIN; + return rc; } @@ -2500,9 +2807,7 @@ success: /* rc == NGX_AGAIN */ [% IF http_subsys %] - if (u->body_downstream - && r->request_body->rest == 0) - { + if (u->body_downstream && r->request_body->rest == 0) { u->eof = 1; } [% END %] @@ -2818,6 +3123,20 @@ ngx_[% subsys %]_lua_socket_tcp_send(lua_State *L) len = ngx_[% subsys %]_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */); break; + case LUA_TNIL: + len = sizeof("nil") - 1; + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, 2)) { + len = sizeof("true") - 1; + + } else { + len = sizeof("false") - 1; + } + + break; + default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "or array table expected, got %s", @@ -2853,6 +3172,29 @@ ngx_[% subsys %]_lua_socket_tcp_send(lua_State *L) b->last = ngx_[% subsys %]_lua_copy_str_in_table(L, -1, b->last); break; + case LUA_TNIL: + *b->last++ = 'n'; + *b->last++ = 'i'; + *b->last++ = 'l'; + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, 2)) { + *b->last++ = 't'; + *b->last++ = 'r'; + *b->last++ = 'u'; + *b->last++ = 'e'; + + } else { + *b->last++ = 'f'; + *b->last++ = 'a'; + *b->last++ = 'l'; + *b->last++ = 's'; + *b->last++ = 'e'; + } + + break; + default: return luaL_error(L, "impossible to reach here"); } @@ -3096,6 +3438,7 @@ ngx_[% subsys %]_lua_socket_tcp_close(lua_State *L) } +[% IF stream_subsys %] static int ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L) { @@ -3103,9 +3446,7 @@ ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L) ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; ngx_str_t direction; char *p; -[% IF stream_subsys %] ngx_[% subsys %]_lua_ctx_t *ctx; -[% END %] if (lua_gettop(L) != 2) { return luaL_error(L, "expecting 2 arguments " @@ -3123,7 +3464,6 @@ ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L) return luaL_error(L, "no request found"); } -[% IF stream_subsys %] ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); if (ctx == NULL) { ngx_[% subsys %]_lua_socket_handle_write_error(r, u, @@ -3150,7 +3490,6 @@ ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L) /* prevent all further output attempt */ ctx->eof = 1; } -[% END %] if (u == NULL || u->peer.connection == NULL @@ -3194,6 +3533,7 @@ ngx_[% subsys %]_lua_socket_tcp_shutdown(lua_State *L) lua_pushinteger(L, 1); return 1; } +[% END %] static int @@ -3474,11 +3814,7 @@ ngx_[% subsys %]_lua_socket_send([% req_type %] *r, } -#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_[% subsys %]_lua_module); @@ -3905,91 +4241,374 @@ ngx_[% subsys %]_lua_socket_tcp_finalize_read_part([% req_type %] *r, return; } - c = u->peer.connection; + c = u->peer.connection; + + if (c) { + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->read->active || c->read->disabled) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } + +#if defined(nginx_version) && nginx_version >= 1007005 + if (c->read->posted) { +#else + if (c->read->prev) { +#endif + ngx_delete_posted_event(c->read); + } + + c->read->closed = 1; + + /* TODO: shutdown the reading part of the connection */ + } +} + + +static void +ngx_[% subsys %]_lua_socket_tcp_finalize_write_part([% req_type %] *r, +[% IF stream_subsys %] + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, int do_shutdown) + +[% ELSIF http_subsys %] + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u) +[% END %] +{ + ngx_connection_t *c; + ngx_[% subsys %]_lua_ctx_t *ctx; + + c = u->peer.connection; + + if (u->write_closed) { + return; + } + + u->write_closed = 1; + + ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + +[% IF stream_subsys %] + if (c && do_shutdown) { + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua shutdown socket write direction"); + } +[% END %] + + if (u->raw_downstream || u->body_downstream) { + if (ctx && ctx->writing_raw_req_socket) { + ctx->writing_raw_req_socket = 0; + if (r->connection->write->timer_set) { + ngx_del_timer(r->connection->write); + } + + r->connection->write->error = 1; + } + return; + } + + if (c) { + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (c->write->active || c->write->disabled) { + ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + } + +#if defined(nginx_version) && nginx_version >= 1007005 + if (c->write->posted) { +#else + if (c->write->prev) { +#endif + ngx_delete_posted_event(c->write); + } + + c->write->closed = 1; + } +} + + +static void +ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_handler(ngx_event_t *ev) +{ + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_ctx_t *ctx; + [% req_type %] *r; + ngx_[% subsys %]_lua_co_ctx_t *coctx; + ngx_[% subsys %]_lua_loc_conf_t *llcf; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = ev->data; + ngx_queue_remove(&conn_op_ctx->queue); + + u = conn_op_ctx->u; + r = u->request; + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + u->write_co_ctx = NULL; + + llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); + + if (llcf->log_socket_errors) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "[% log_prefix %]lua tcp socket queued connect " + "timed out, when trying to connect to %V:%ud", + &conn_op_ctx->host, conn_op_ctx->port); + } + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + u->socket_pool->connections--; + + ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + return; + } + + ctx->cur_co_ctx = coctx; + + ngx_[% subsys %]_lua_assert(coctx && (!ngx_[% subsys %]_lua_is_thread(ctx) + || coctx->co_ref >= 0)); + + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket waking up the current " + "request"); + + u->write_prepare_retvals = + ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_retval_handler; + + if (ctx->entered_content_phase) { + (void) ngx_[% subsys %]_lua_socket_tcp_conn_op_resume(r); + + } else { + ctx->resume_handler = ngx_[% subsys %]_lua_socket_tcp_conn_op_resume; + ngx_[% req_subsys %]_core_run_phases(r); + } + +[% IF http_subsys %] + ngx_http_run_posted_requests(r->connection); +[% END %] +} + + +static int +ngx_[% subsys %]_lua_socket_tcp_conn_op_timeout_retval_handler( + [% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, + lua_State *L) +{ + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + return 2; +} + + +static void +ngx_[% subsys %]_lua_socket_tcp_resume_conn_op( + ngx_[% subsys %]_lua_socket_pool_t *spool) +{ + ngx_queue_t *q; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + +#if (NGX_DEBUG) + ngx_[% subsys %]_lua_assert(spool->connections >= 0); + +#else + if (spool->connections < 0) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "[% log_prefix %]lua tcp socket connections count " + "mismatched for connection pool \"%s\", connections: " + "%i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = 0; + } +#endif + + /* we manually destroy wait_connect_op before triggering connect + * operation resumption, so that there is no resumption happens when Nginx + * is exiting. + */ + if (ngx_queue_empty(&spool->wait_connect_op)) { + return; + } + + q = ngx_queue_head(&spool->wait_connect_op); + conn_op_ctx = ngx_queue_data(q, + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua tcp socket post connect operation " + "resumption u: %p, ctx: %p for connection pool \"%s\", " + "connections: %i", + conn_op_ctx->u, conn_op_ctx, spool->key, spool->connections); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + conn_op_ctx->event.handler = + ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_handler; - if (c) { - if (c->read->timer_set) { - ngx_del_timer(c->read); - } + ngx_post_event((&conn_op_ctx->event), &ngx_posted_events); +} - if (c->read->active || c->read->disabled) { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); - } -#if defined(nginx_version) && nginx_version >= 1007005 - if (c->read->posted) { -#else - if (c->read->prev) { -#endif - ngx_delete_posted_event(c->read); - } +static void +ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_cleanup(void *data) +{ + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx = data; - c->read->closed = 1; + u = conn_op_ctx->u; - /* TODO: shutdown the reading part of the connection */ - } +[% IF http_subsys %] + ngx_log_debug3(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, + "[% log_prefix %]cleanup lua tcp socket " + "conn_op_ctx: %p, u: %p, request: \"%V\"", + conn_op_ctx, u, &u->request->uri); + +[% ELSIF stream_subsys %] + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], u->request->connection->log, 0, + "[% log_prefix %]cleanup lua tcp socket " + "conn_op_ctx: %p, u: %p", + conn_op_ctx, u); +[% END %] + + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); } static void -ngx_[% subsys %]_lua_socket_tcp_finalize_write_part([% req_type %] *r, - ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, int do_shutdown) +ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_handler(ngx_event_t *ev) { - ngx_connection_t *c; - ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_queue_t *q; + [% req_type %] *r; + ngx_[% req_subsys %]_cleanup_t *cln; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_co_ctx_t *coctx; + ngx_[% subsys %]_lua_socket_pool_t *spool; + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - c = u->peer.connection; + conn_op_ctx = ev->data; + u = conn_op_ctx->u; + r = u->request; + spool = u->socket_pool; + + if (ngx_queue_empty(&spool->wait_connect_op)) { +#if (NGX_DEBUG) + ngx_[% subsys %]_lua_assert(!(spool->backlog >= 0 + && spool->connections > spool->size)); + +#else + if (spool->backlog >= 0 && spool->connections > spool->size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "[% log_prefix %]lua tcp socket connections count " + "mismatched for connection pool \"%s\", connections: " + "%i, size: %i", + spool->key, spool->connections, spool->size); + spool->connections = spool->size; + } +#endif - if (u->write_closed) { return; } - u->write_closed = 1; + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + + coctx = u->write_co_ctx; + coctx->cleanup = NULL; + /* note that we store conn_op_ctx in coctx->data instead of u */ + coctx->data = conn_op_ctx; + /* clear ngx_[% subsys %]_lua_tcp_queue_conn_op_cleanup */ + u->write_co_ctx = NULL; ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + ngx_queue_insert_head(&spool->cache_connect_op, + &conn_op_ctx->queue); + return; + } - if (c && do_shutdown) { - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - return; - } + ctx->cur_co_ctx = coctx; - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua shutdown socket write direction"); - } + ngx_[% subsys %]_lua_assert(coctx && (!ngx_[% subsys %]_lua_is_thread(ctx) + || coctx->co_ref >= 0)); - if (u->raw_downstream || u->body_downstream) { - if (ctx && ctx->writing_raw_req_socket) { - ctx->writing_raw_req_socket = 0; - if (r->connection->write->timer_set) { - ngx_del_timer(r->connection->write); - } + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "[% log_prefix %]lua tcp socket waking up the current " + "request"); - r->connection->write->error = 1; + u->write_prepare_retvals = + ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_retval_handler; + + if (ctx->entered_content_phase) { + (void) ngx_[% subsys %]_lua_socket_tcp_conn_op_resume(r); + + } else { + cln = ngx_[% subsys %]_lua_cleanup_add(r, 0); + if (cln != NULL) { + cln->handler = ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_cleanup; + cln->data = conn_op_ctx; + conn_op_ctx->cleanup = &cln->handler; } - return; + + ctx->resume_handler = ngx_[% subsys %]_lua_socket_tcp_conn_op_resume; + ngx_[% req_subsys %]_core_run_phases(r); } - if (c) { - if (c->write->timer_set) { - ngx_del_timer(c->write); - } +[% IF http_subsys %] + ngx_http_run_posted_requests(r->connection); +[% END %] +} - if (c->write->active || c->write->disabled) { - ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); - } -#if defined(nginx_version) && nginx_version >= 1007005 - if (c->write->posted) { -#else - if (c->write->prev) { -#endif - ngx_delete_posted_event(c->write); - } +static int +ngx_[% subsys %]_lua_socket_tcp_conn_op_resume_retval_handler([% req_type %] *r, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u, lua_State *L) +{ + int nret; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_co_ctx_t *coctx; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; - c->write->closed = 1; + ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + coctx = ctx->cur_co_ctx; + dd("coctx: %p", coctx); + conn_op_ctx = coctx->data; + if (conn_op_ctx->cleanup != NULL) { + *conn_op_ctx->cleanup = NULL; + ngx_[% subsys %]_lua_cleanup_free(r, conn_op_ctx->cleanup); + conn_op_ctx->cleanup = NULL; } + + /* decrease pending connect operation counter */ + u->socket_pool->connections--; + + nret = ngx_[% subsys %]_lua_socket_tcp_connect_helper(L, u, r, ctx, + conn_op_ctx->host.data, + conn_op_ctx->host.len, + conn_op_ctx->port, 1); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + return nret; } @@ -4013,7 +4632,13 @@ ngx_[% subsys %]_lua_socket_tcp_finalize([% req_type %] *r, } ngx_[% subsys %]_lua_socket_tcp_finalize_read_part(r, u); + +[% IF http_subsys %] + ngx_[% subsys %]_lua_socket_tcp_finalize_write_part(r, u); + +[% ELSIF stream_subsys %] ngx_[% subsys %]_lua_socket_tcp_finalize_write_part(r, u, 0); +[% END %] if (u->raw_downstream || u->body_downstream) { u->peer.connection = NULL; @@ -4045,20 +4670,21 @@ ngx_[% subsys %]_lua_socket_tcp_finalize([% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_close_connection(c); u->peer.connection = NULL; - if (!u->reused) { - return; - } + u->conn_closed = 1; spool = u->socket_pool; if (spool == NULL) { return; } - spool->active_connections--; + spool->connections--; - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_[% subsys %]_lua_socket_free_pool(r->connection->log, spool); + return; } + + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(spool); } } @@ -4788,13 +5414,11 @@ ngx_[% subsys %]_lua_req_socket_tcp(lua_State *L) } #endif -#if nginx_version >= 1003009 if (!raw && r->headers_in.chunked) { lua_pushnil(L); lua_pushliteral(L, "chunked request bodies not supported yet"); return 2; } -#endif [% END %] ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); @@ -4815,12 +5439,6 @@ ngx_[% subsys %]_lua_req_socket_tcp(lua_State *L) c = r->connection; if (raw) { -#if !defined(nginx_version) || nginx_version < 1003013 - lua_pushnil(L); - lua_pushliteral(L, "nginx version too old"); - return 2; -#else - [% IF http_subsys %] if (r->request_body) { if (r->request_body->rest > 0) { @@ -4882,7 +5500,6 @@ ngx_[% subsys %]_lua_req_socket_tcp(lua_State *L) r->keepalive = 0; r->lingering_close = 1; [% END %] -#endif } else { [% IF http_subsys %] @@ -5078,21 +5695,19 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) ngx_[% subsys %]_lua_loc_conf_t *llcf; ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; ngx_[% subsys %]_lua_socket_pool_t *spool; - ngx_[% subsys %]_lua_socket_pool_item_t *items, *item; + ngx_[% subsys %]_lua_socket_pool_item_t *item; ngx_connection_t *c; - size_t size, key_len; ngx_str_t key; - ngx_uint_t i; ngx_queue_t *q; ngx_peer_connection_t *pc; - u_char *p; [% req_type %] *r; ngx_msec_t timeout; - ngx_uint_t pool_size; + ngx_int_t pool_size; int n; ngx_int_t rc; ngx_buf_t *b; + const char *msg; n = lua_gettop(L); @@ -5103,18 +5718,6 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - - lua_rawgeti(L, 1, SOCKET_KEY_INDEX); - key.data = (u_char *) lua_tolstring(L, -1, &key.len); - if (key.data == NULL) { - lua_pushnil(L); - lua_pushliteral(L, "key not found"); - return 2; - } - lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); @@ -5125,7 +5728,7 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } - /* stack: obj cache key */ + /* stack: obj timeout? size? */ pc = &u->peer; c = pc->connection; @@ -5177,10 +5780,34 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) return 2; } + if (ngx_terminate || ngx_exiting) { + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, + "[% log_prefix %]lua tcp socket set keepalive while " + "process exiting, closing connection %p", c); + + ngx_[% subsys %]_lua_socket_tcp_finalize(r, u); + lua_pushinteger(L, 1); + return 1; + } + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, "[% log_prefix %]lua tcp socket set keepalive: saving " "connection %p", c); + lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( + socket_pool_key)); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* stack: obj timeout? size? pools */ + + lua_rawgeti(L, 1, SOCKET_KEY_INDEX); + key.data = (u_char *) lua_tolstring(L, -1, &key.len); + if (key.data == NULL) { + lua_pushnil(L); + lua_pushliteral(L, "key not found"); + return 2; + } + dd("saving connection to key %s", lua_tostring(L, -1)); lua_pushvalue(L, -1); @@ -5188,7 +5815,7 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) spool = lua_touserdata(L, -1); lua_pop(L, 1); - /* stack: obj timeout? size? cache key */ + /* stack: obj timeout? size? pools cache_key */ llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); @@ -5202,85 +5829,50 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) pool_size = llcf->pool_size; } - if (pool_size == 0) { - lua_pushnil(L); - lua_pushliteral(L, "zero pool size"); - return 2; - } - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "[% log_prefix %]lua tcp socket connection pool size: %ui", - pool_size); - - key_len = ngx_align(key.len + 1, sizeof(void *)); - - size = sizeof(ngx_[% subsys %]_lua_socket_pool_t) + key_len - 1 - + sizeof(ngx_[% subsys %]_lua_socket_pool_item_t) - * pool_size; - - spool = lua_newuserdata(L, size); - if (spool == NULL) { - return luaL_error(L, "no memory"); + if (pool_size <= 0) { + msg = lua_pushfstring(L, "bad \"pool_size\" option value: %i", + pool_size); + return luaL_argerror(L, n, msg); } - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - pool_udata_metatable_key)); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); - - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, - "[% log_prefix %]lua tcp socket keepalive create " - "connection pool for key" " \"%s\"", - lua_tostring(L, -2)); - - lua_rawset(L, -3); - - spool->active_connections = 0; - spool->lua_vm = ngx_[% subsys %]_lua_get_lua_vm(r, NULL); - - ngx_queue_init(&spool->cache); - ngx_queue_init(&spool->free); - - p = ngx_copy(spool->key, key.data, key.len); - *p++ = '\0'; - - items = (ngx_[% subsys %]_lua_socket_pool_item_t *) (spool->key + key_len); - - dd("items: %p", items); - - ngx_[% subsys %]_lua_assert((void *) items - == ngx_align_ptr(items, sizeof(void *))); - - for (i = 0; i < pool_size; i++) { - ngx_queue_insert_head(&spool->free, &items[i].queue); - items[i].socket_pool = spool; - } + ngx_[% subsys %]_lua_socket_tcp_create_socket_pool(L, r, key, + pool_size, -1, + &spool); } if (ngx_queue_empty(&spool->free)) { q = ngx_queue_last(&spool->cache); ngx_queue_remove(q); - spool->active_connections--; item = ngx_queue_data(q, ngx_[% subsys %]_lua_socket_pool_item_t, queue); ngx_[% subsys %]_lua_socket_tcp_close_connection(item->connection); + /* only decrease the counter for connections which were counted */ + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + } + } else { q = ngx_queue_head(&spool->free); ngx_queue_remove(q); item = ngx_queue_data(q, ngx_[% subsys %]_lua_socket_pool_item_t, queue); + + /* we should always increase connections after getting connected, + * and decrease connections after getting closed. + * however, we don't create connection pool in previous connect method. + * so we increase connections here for backward compatibility. + */ + if (u->socket_pool == NULL) { + spool->connections++; + } } item->connection = c; ngx_queue_insert_head(&spool->cache, q); - if (!u->reused) { - spool->active_connections++; - } - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, "[% log_prefix %]lua tcp socket clear current socket connection"); @@ -5350,51 +5942,36 @@ ngx_[% subsys %]_lua_socket_tcp_setkeepalive(lua_State *L) ngx_[% subsys %]_lua_socket_tcp_finalize(r, u); #endif + /* since we set u->peer->connection to NULL previously, the connect + * operation won't be resumed in the + * ngx_[% subsys %]_lua_socket_tcp_finalize. + * Therefore we need to resume it here. + */ + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(spool); + lua_pushinteger(L, 1); return 1; } static ngx_int_t -ngx_[% subsys %]_lua_get_keepalive_peer([% req_type %] *r, lua_State *L, - int key_index, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u) +ngx_[% subsys %]_lua_get_keepalive_peer([% req_type %] *r, + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u) { ngx_[% subsys %]_lua_socket_pool_item_t *item; ngx_[% subsys %]_lua_socket_pool_t *spool; ngx_[% req_subsys %]_cleanup_t *cln; ngx_queue_t *q; - int top; ngx_peer_connection_t *pc; ngx_connection_t *c; - top = lua_gettop(L); - - if (key_index < 0) { - key_index = top + key_index + 1; - } - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, "[% log_prefix %]lua tcp socket pool get keepalive peer"); pc = &u->peer; - lua_pushlightuserdata(L, ngx_[% subsys %]_lua_lightudata_mask( - socket_pool_key)); - lua_rawget(L, LUA_REGISTRYINDEX); /* table */ - lua_pushvalue(L, key_index); /* key */ - lua_rawget(L, -2); - - spool = lua_touserdata(L, -1); - if (spool == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, - "[% log_prefix %]lua tcp socket keepalive connection " - "pool not found"); - lua_settop(L, top); - return NGX_DECLINED; - } - - u->socket_pool = spool; + spool = u->socket_pool; if (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5439,7 +6016,6 @@ ngx_[% subsys %]_lua_get_keepalive_peer([% req_type %] *r, lua_State *L, cln = ngx_[% subsys %]_lua_cleanup_add(r, 0); if (cln == NULL) { u->ft_type |= NGX_[% SUBSYS %]_LUA_SOCKET_FT_ERROR; - lua_settop(L, top); return NGX_ERROR; } @@ -5448,16 +6024,12 @@ ngx_[% subsys %]_lua_get_keepalive_peer([% req_type %] *r, lua_State *L, u->cleanup = &cln->handler; } - lua_settop(L, top); - return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], pc->log, 0, "[% log_prefix %]lua tcp socket keepalive: connection pool empty"); - lua_settop(L, top); - return NGX_DECLINED; } @@ -5466,7 +6038,7 @@ static void ngx_[% subsys %]_lua_socket_keepalive_dummy_handler(ngx_event_t *ev) { ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ev->log, 0, - "keepalive dummy handler"); + "[% log_prefix %]keepalive dummy handler"); } @@ -5531,13 +6103,15 @@ close: ngx_queue_remove(&item->queue); ngx_queue_insert_head(&spool->free, &item->queue); - spool->active_connections--; + spool->connections--; - dd("keepalive: active connections: %u", - (unsigned) spool->active_connections); + dd("keepalive: connections: %u", (unsigned) spool->connections); - if (spool->active_connections == 0) { + if (spool->connections == 0) { ngx_[% subsys %]_lua_socket_free_pool(ev->log, spool); + + } else { + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(spool); } return NGX_DECLINED; @@ -5551,8 +6125,8 @@ ngx_[% subsys %]_lua_socket_free_pool(ngx_log_t *log, lua_State *L; ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, - "[% log_prefix %]lua tcp socket keepalive: free connection pool " - "for \"%s\"", spool->key); + "[% log_prefix %]lua tcp socket keepalive: free " + "connection pool for \"%s\"", spool->key); L = spool->lua_vm; @@ -5567,11 +6141,13 @@ ngx_[% subsys %]_lua_socket_free_pool(ngx_log_t *log, static void -ngx_[% subsys %]_lua_socket_shutdown_pool_helper(ngx_[% subsys %]_lua_socket_pool_t *spool) +ngx_[% subsys %]_lua_socket_shutdown_pool_helper( + ngx_[% subsys %]_lua_socket_pool_t *spool) { - ngx_queue_t *q; - ngx_connection_t *c; - ngx_[% subsys %]_lua_socket_pool_item_t *item; + ngx_queue_t *q; + ngx_connection_t *c; + ngx_[% subsys %]_lua_socket_pool_item_t *item; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; while (!ngx_queue_empty(&spool->cache)) { q = ngx_queue_head(&spool->cache); @@ -5585,7 +6161,29 @@ ngx_[% subsys %]_lua_socket_shutdown_pool_helper(ngx_[% subsys %]_lua_socket_poo ngx_queue_insert_head(&spool->free, q); } - spool->active_connections = 0; + while (!ngx_queue_empty(&spool->cache_connect_op)) { + q = ngx_queue_head(&spool->cache_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t, + queue); + ngx_[% subsys %]_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + while (!ngx_queue_empty(&spool->wait_connect_op)) { + q = ngx_queue_head(&spool->wait_connect_op); + ngx_queue_remove(q); + conn_op_ctx = ngx_queue_data(q, ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t, + queue); + + if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_[% subsys %]_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx); + } + + /* spool->connections will be decreased down to zero in + * ngx_[% subsys %]_lua_socket_tcp_finalize */ } @@ -5841,6 +6439,14 @@ static ngx_int_t ngx_[% subsys %]_lua_socket_insert_buffer( } +static ngx_int_t +ngx_[% subsys %]_lua_socket_tcp_conn_op_resume([% req_type %] *r) +{ + return ngx_[% subsys %]_lua_socket_tcp_resume_helper(r, + SOCKET_OP_RESUME_CONN); +} + + static ngx_int_t ngx_[% subsys %]_lua_socket_tcp_conn_resume([% req_type %] *r) { @@ -5871,11 +6477,12 @@ ngx_[% subsys %]_lua_socket_tcp_resume_helper([% req_type %] *r, ngx_int_t rc; ngx_uint_t nreqs; ngx_connection_t *c; - ngx_[% subsys %]_lua_ctx_t *ctx; - ngx_[% subsys %]_lua_co_ctx_t *coctx; - ngx_[% subsys %]_lua_socket_tcp_retval_handler prepare_retvals; + ngx_[% subsys %]_lua_ctx_t *ctx; + ngx_[% subsys %]_lua_co_ctx_t *coctx; ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + ngx_[% subsys %]_lua_socket_tcp_retval_handler prepare_retvals; ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); if (ctx == NULL) { @@ -5885,21 +6492,29 @@ ngx_[% subsys %]_lua_socket_tcp_resume_helper([% req_type %] *r, ctx->resume_handler = ngx_[% subsys %]_lua_wev_handler; ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua tcp operation done, resuming lua thread"); + "[% log_prefix %]lua tcp operation done, resuming lua " + "thread"); coctx = ctx->cur_co_ctx; dd("coctx: %p", coctx); - u = coctx->data; - switch (socket_op) { + + case SOCKET_OP_RESUME_CONN: + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + prepare_retvals = u->write_prepare_retvals; + break; + case SOCKET_OP_CONNECT: case SOCKET_OP_WRITE: + u = coctx->data; prepare_retvals = u->write_prepare_retvals; break; case SOCKET_OP_READ: + u = coctx->data; prepare_retvals = u->read_prepare_retvals; break; @@ -5913,6 +6528,15 @@ ngx_[% subsys %]_lua_socket_tcp_resume_helper([% req_type %] *r, "u:%p", prepare_retvals, u); nret = prepare_retvals(r, u, ctx->cur_co_ctx->co); + if (socket_op == SOCKET_OP_CONNECT + && nret > 1 + && !u->conn_closed + && u->socket_pool != NULL) + { + u->socket_pool->connections--; + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + if (nret == NGX_AGAIN) { return NGX_DONE; } @@ -5924,7 +6548,7 @@ ngx_[% subsys %]_lua_socket_tcp_resume_helper([% req_type %] *r, rc = ngx_[% subsys %]_lua_run_thread(vm, r, ctx, nret); ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "lua run thread returned %d", rc); + "[% log_prefix %]lua run thread returned %d", rc); if (rc == NGX_AGAIN) { return ngx_[% subsys %]_lua_run_posted_threads(c, vm, r, ctx, nreqs); @@ -5944,6 +6568,37 @@ ngx_[% subsys %]_lua_socket_tcp_resume_helper([% req_type %] *r, } +static void +ngx_[% subsys %]_lua_tcp_queue_conn_op_cleanup(void *data) +{ + ngx_[% subsys %]_lua_co_ctx_t *coctx = data; + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t *conn_op_ctx; + + conn_op_ctx = coctx->data; + u = conn_op_ctx->u; + + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]lua tcp socket abort queueing, " + "conn_op_ctx: %p, u: %p", + conn_op_ctx, u); + + if (conn_op_ctx->event.posted) { + ngx_delete_posted_event(&conn_op_ctx->event); + + } else if (conn_op_ctx->event.timer_set) { + ngx_del_timer(&conn_op_ctx->event); + } + + ngx_queue_remove(&conn_op_ctx->queue); + ngx_queue_insert_head(&u->socket_pool->cache_connect_op, + &conn_op_ctx->queue); + + u->socket_pool->connections--; + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(u->socket_pool); +} + + static void ngx_[% subsys %]_lua_tcp_resolve_cleanup(void *data) { @@ -5959,6 +6614,11 @@ ngx_[% subsys %]_lua_tcp_resolve_cleanup(void *data) return; } + if (u->socket_pool != NULL) { + u->socket_pool->connections--; + ngx_[% subsys %]_lua_socket_tcp_resume_conn_op(u->socket_pool); + } + rctx = u->resolved->ctx; if (rctx == NULL) { return; diff --git a/src/subsys/ngx_subsys_lua_socket_tcp.h.tt2 b/src/subsys/ngx_subsys_lua_socket_tcp.h.tt2 index 686a213..09b5b0f 100644 --- a/src/subsys/ngx_subsys_lua_socket_tcp.h.tt2 +++ b/src/subsys/ngx_subsys_lua_socket_tcp.h.tt2 @@ -35,17 +35,39 @@ typedef void (*ngx_[% subsys %]_lua_socket_tcp_upstream_handler_pt) ([% req_type %] *r, ngx_[% subsys %]_lua_socket_tcp_upstream_t *u); +typedef struct { + ngx_event_t event; + ngx_queue_t queue; + ngx_str_t host; + ngx_[% req_subsys %]_cleanup_pt *cleanup; + ngx_[% subsys %]_lua_socket_tcp_upstream_t *u; + in_port_t port; +} ngx_[% subsys %]_lua_socket_tcp_conn_op_ctx_t; + + +#define ngx_[% subsys %]_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \ + ngx_free(conn_op_ctx->host.data); \ + ngx_free(conn_op_ctx) + + typedef struct { lua_State *lua_vm; - /* active connections == out-of-pool reused connections - * + in-pool connections */ - ngx_uint_t active_connections; + ngx_int_t size; + ngx_queue_t cache_connect_op; + ngx_queue_t wait_connect_op; + + /* connections == active connections + pending connect operations, + * while active connections == out-of-pool reused connections + * + in-pool connections */ + ngx_int_t connections; /* queues of ngx_[% subsys %]_lua_socket_pool_item_t: */ ngx_queue_t cache; ngx_queue_t free; + ngx_int_t backlog; + u_char key[1]; } ngx_[% subsys %]_lua_socket_pool_t; @@ -105,6 +127,7 @@ struct ngx_[% subsys %]_lua_socket_tcp_upstream_s { unsigned raw_downstream:1; unsigned read_closed:1; unsigned write_closed:1; + unsigned conn_closed:1; [% IF stream_subsys %] unsigned read_consumed:1; [% END %] diff --git a/src/subsys/ngx_subsys_lua_socket_udp.c.tt2 b/src/subsys/ngx_subsys_lua_socket_udp.c.tt2 index 759844a..7fb37b8 100644 --- a/src/subsys/ngx_subsys_lua_socket_udp.c.tt2 +++ b/src/subsys/ngx_subsys_lua_socket_udp.c.tt2 @@ -188,6 +188,7 @@ ngx_[% subsys %]_lua_socket_udp(lua_State *L) [% IF http_subsys %] | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH [% ELSIF stream_subsys %] | NGX_STREAM_LUA_CONTEXT_PREREAD [% END %] @@ -259,6 +260,7 @@ ngx_[% subsys %]_lua_socket_udp_setpeername(lua_State *L) [% IF http_subsys %] | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH [% ELSIF stream_subsys %] | NGX_STREAM_LUA_CONTEXT_PREREAD @@ -427,9 +429,6 @@ ngx_[% subsys %]_lua_socket_udp_setpeername(lua_State *L) } rctx->name = host; -#if !defined(nginx_version) || nginx_version < 1005008 - rctx->type = NGX_RESOLVE_A; -#endif rctx->handler = ngx_[% subsys %]_lua_socket_resolve_handler; rctx->data = u; rctx->timeout = clcf->resolver_timeout; @@ -500,12 +499,8 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) lua_State *L; u_char *p; size_t len; -#if defined(nginx_version) && nginx_version >= 1005008 socklen_t socklen; struct sockaddr *sockaddr; -#else - struct sockaddr_in *sin; -#endif ngx_uint_t i; unsigned waiting; @@ -581,36 +576,19 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) #if (NGX_DEBUG) { -# if defined(nginx_version) && nginx_version >= 1005008 - u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; -# else - in_addr_t addr; -# endif - ngx_uint_t i; - -# if defined(nginx_version) && nginx_version >= 1005008 - addr.data = text; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; + ngx_uint_t i; - for (i = 0; i < ctx->naddrs; i++) { - addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, - text, NGX_SOCKADDR_STRLEN, 0); + addr.data = text; - ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, - "name was resolved to %V", &addr); - } -# else - for (i = 0; i < ctx->naddrs; i++) { - dd("addr i: %d %p", (int) i, &ctx->addrs[i]); - - addr = ntohl(ctx->addrs[i]); + for (i = 0; i < ctx->naddrs; i++) { + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); - ngx_log_debug4(NGX_LOG_DEBUG_[% SUBSYS %], c->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); - } -# endif + ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, + "name was resolved to %V", &addr); + } } #endif @@ -625,7 +603,6 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) dd("selected addr index: %d", (int) i); -#if defined(nginx_version) && nginx_version >= 1005008 socklen = ur->addrs[i].socklen; sockaddr = ngx_palloc(r->pool, socklen); @@ -653,31 +630,6 @@ ngx_[% subsys %]_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx) len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); ur->sockaddr = sockaddr; ur->socklen = socklen; - -#else - /* for nginx older than 1.5.8 */ - - len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; - - p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in)); - if (p == NULL) { - goto nomem; - } - - sin = (struct sockaddr_in *) &p[len]; - ngx_memzero(sin, sizeof(struct sockaddr_in)); - - len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN); - len = ngx_sprintf(&p[len], ":%d", ur->port) - p; - - sin->sin_family = AF_INET; - sin->sin_port = htons(ur->port); - sin->sin_addr.s_addr = ur->addrs[i]; - - ur->sockaddr = (struct sockaddr *) sin; - ur->socklen = sizeof(struct sockaddr_in); -#endif - ur->host.data = p; ur->host.len = len; ur->naddrs = 1; @@ -847,11 +799,7 @@ ngx_[% subsys %]_lua_socket_error_retval_handler([% req_type %] *r, } else { if (u->socket_errno) { -#if defined(nginx_version) && nginx_version >= 9000 p = ngx_strerror(u->socket_errno, errstr, sizeof(errstr)); -#else - p = ngx_strerror_r(u->socket_errno, errstr, sizeof(errstr)); -#endif /* for compatibility with LuaSocket */ ngx_strlow(errstr, errstr, p - errstr); lua_pushlstring(L, (char *) errstr, p - errstr); @@ -934,6 +882,20 @@ ngx_[% subsys %]_lua_socket_udp_send(lua_State *L) len = ngx_[% subsys %]_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */); break; + case LUA_TNIL: + len = sizeof("nil") - 1; + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, 2)) { + len = sizeof("true") - 1; + + } else { + len = sizeof("false") - 1; + } + + break; + default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "or array table expected, got %s", @@ -956,6 +918,32 @@ ngx_[% subsys %]_lua_socket_udp_send(lua_State *L) (void) ngx_[% subsys %]_lua_copy_str_in_table(L, 2, query.data); break; + case LUA_TNIL: + p = query.data; + *p++ = 'n'; + *p++ = 'i'; + *p++ = 'l'; + break; + + case LUA_TBOOLEAN: + p = query.data; + + if (lua_toboolean(L, 2)) { + *p++ = 't'; + *p++ = 'r'; + *p++ = 'u'; + *p++ = 'e'; + + } else { + *p++ = 'f'; + *p++ = 'a'; + *p++ = 'l'; + *p++ = 's'; + *p++ = 'e'; + } + + break; + default: return luaL_error(L, "impossible to reach here"); } @@ -970,10 +958,17 @@ ngx_[% subsys %]_lua_socket_udp_send(lua_State *L) dd("sending query %.*s", (int) query.len, query.data); - n = ngx_udp_send(u->udp_connection.connection, query.data, query.len); +[% IF http_subsys %] + n = ngx_send(u->udp_connection.connection, query.data, query.len); dd("ngx_send returns %d (query len %d)", (int) n, (int) query.len); +[% ELSIF stream_subsys %] + n = ngx_udp_send(u->udp_connection.connection, query.data, query.len); + + dd("ngx_udp_send returns %d (query len %d)", (int) n, (int) query.len); +[% END %] + if (n == NGX_ERROR || n == NGX_AGAIN) { u->socket_errno = ngx_socket_errno; @@ -1209,11 +1204,16 @@ ngx_[% subsys %]_lua_socket_udp_finalize([% req_type %] *r, u->resolved->ctx = NULL; } +[% IF stream_subsys %] /* * do not close if it is a downstream connection as that will * be handled by stream subsystem itself */ if (u->udp_connection.connection && !u->raw_downstream) { + +[% ELSIF http_subsys %] + if (u->udp_connection.connection) { +[% END %] ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], r->connection->log, 0, "lua close socket connection"); diff --git a/src/subsys/ngx_subsys_lua_socket_udp.h.tt2 b/src/subsys/ngx_subsys_lua_socket_udp.h.tt2 index ae82753..e7a2560 100644 --- a/src/subsys/ngx_subsys_lua_socket_udp.h.tt2 +++ b/src/subsys/ngx_subsys_lua_socket_udp.h.tt2 @@ -54,7 +54,10 @@ struct ngx_[% subsys %]_lua_socket_udp_upstream_s { ngx_[% subsys %]_lua_co_ctx_t *co_ctx; unsigned waiting:1; + +[% IF stream_subsys %] unsigned raw_downstream:1; +[% END %] }; diff --git a/src/subsys/ngx_subsys_lua_ssl_certby.c.tt2 b/src/subsys/ngx_subsys_lua_ssl_certby.c.tt2 index f2ecca7..b3018be 100644 --- a/src/subsys/ngx_subsys_lua_ssl_certby.c.tt2 +++ b/src/subsys/ngx_subsys_lua_ssl_certby.c.tt2 @@ -206,7 +206,7 @@ ngx_[% subsys %]_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], c->log, 0, - "stream ssl cert: connection reusable: %ud", c->reusable); + "[% log_prefix %]ssl cert: connection reusable: %ud", c->reusable); cctx = ngx_[% subsys %]_lua_ssl_get_ctx(c->ssl->connection); @@ -217,7 +217,7 @@ ngx_[% subsys %]_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) if (cctx->done) { ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], c->log, 0, - "stream lua_certificate_by_lua:" + "[% log_prefix %]lua_certificate_by_lua:" " cert cb exit code: %d", cctx->exit_code); @@ -283,38 +283,19 @@ ngx_[% subsys %]_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) cscf = ngx_stream_get_module_srv_conf(fs, ngx_stream_core_module); [% END %] -#if defined(nginx_version) && nginx_version >= 1003014 - -# if nginx_version >= 1009000 - +#if defined(nginx_version) && nginx_version >= 1009000 [% IF http_subsys %] ngx_set_connection_log(fc, clcf->error_log); [% ELSIF stream_subsys %] ngx_set_connection_log(fc, cscf->error_log); [% END %] -# else - -[% IF http_subsys %] - ngx_http_set_connection_log(fc, clcf->error_log); -[% ELSIF stream_subsys %] -# error "stream ssl_cert_by_lua only supports nginx >= 1.13.0" -[% END %] - -# endif - #else - [% IF http_subsys %] - fc->log->file = clcf->error_log->file; - - if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - fc->log->log_level = clcf->error_log->log_level; - } + ngx_http_set_connection_log(fc, clcf->error_log); [% ELSIF stream_subsys %] # error "stream ssl_cert_by_lua only supports nginx >= 1.13.0" [% END %] - #endif if (cctx == NULL) { @@ -372,7 +353,7 @@ ngx_[% subsys %]_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) } ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], c->log, 0, - "stream lua_certificate_by_lua:" + "[% log_prefix %]lua_certificate_by_lua:" " handler return value: %i, " "cert cb exit code: %d", rc, cctx->exit_code); @@ -461,7 +442,7 @@ ngx_[% subsys %]_lua_ssl_cert_aborted(void *data) } ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], cctx->connection->log, 0, - "stream lua_certificate_by_lua: cert cb aborted"); + "[% log_prefix %]lua_certificate_by_lua: cert cb aborted"); cctx->aborted = 1; cctx->request->connection->ssl = NULL; @@ -539,7 +520,7 @@ ngx_[% subsys %]_lua_ssl_cert_by_chunk(lua_State *L, [% req_type %] *r) if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "stream lua: failed to create new" + "[% log_prefix %]failed to create new" " coroutine to handle request"); rc = NGX_ERROR; @@ -602,10 +583,6 @@ ngx_[% subsys %]_lua_ssl_cert_by_chunk(lua_State *L, [% req_type %] *r) } -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] - int ngx_[% subsys %]_lua_ffi_ssl_get_tls1_version([% req_type %] *r, char **err) { @@ -1373,9 +1350,6 @@ failed: return NGX_ERROR; } -[% IF http_subsys %] -#endif /* NGX_LUA_NO_FFI_API */ -[% END %] #endif /* NGX_[% SUBSYS %]_SSL */ diff --git a/src/subsys/ngx_subsys_lua_string.c.tt2 b/src/subsys/ngx_subsys_lua_string.c.tt2 index 9ee2f18..136a507 100644 --- a/src/subsys/ngx_subsys_lua_string.c.tt2 +++ b/src/subsys/ngx_subsys_lua_string.c.tt2 @@ -27,30 +27,13 @@ #endif -#ifndef SHA_DIGEST_LENGTH -#define SHA_DIGEST_LENGTH 20 -#endif - - -static uintptr_t ngx_[% subsys %]_lua_ngx_escape_sql_str(u_char *dst, u_char *src, - size_t size); -static int ngx_[% subsys %]_lua_ngx_escape_uri(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_unescape_uri(lua_State *L); +static uintptr_t ngx_[% subsys %]_lua_ngx_escape_sql_str(u_char *dst, + u_char *src, size_t size); static int ngx_[% subsys %]_lua_ngx_quote_sql_str(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_md5(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_md5_bin(lua_State *L); - -#if (NGX_HAVE_SHA1) -static int ngx_[% subsys %]_lua_ngx_sha1_bin(lua_State *L); -#endif - -static int ngx_[% subsys %]_lua_ngx_decode_base64(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_encode_base64(lua_State *L); static int ngx_[% subsys %]_lua_ngx_crc32_short(lua_State *L); static int ngx_[% subsys %]_lua_ngx_crc32_long(lua_State *L); static int ngx_[% subsys %]_lua_ngx_encode_args(lua_State *L); static int ngx_[% subsys %]_lua_ngx_decode_args(lua_State *L); - #if (NGX_OPENSSL) static int ngx_[% subsys %]_lua_ngx_hmac_sha1(lua_State *L); #endif @@ -59,12 +42,6 @@ static int ngx_[% subsys %]_lua_ngx_hmac_sha1(lua_State *L); void ngx_[% subsys %]_lua_inject_string_api(lua_State *L) { - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_escape_uri); - lua_setfield(L, -2, "escape_uri"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_unescape_uri); - lua_setfield(L, -2, "unescape_uri"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_encode_args); lua_setfield(L, -2, "encode_args"); @@ -74,23 +51,6 @@ ngx_[% subsys %]_lua_inject_string_api(lua_State *L) lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_quote_sql_str); lua_setfield(L, -2, "quote_sql_str"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_decode_base64); - lua_setfield(L, -2, "decode_base64"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_encode_base64); - lua_setfield(L, -2, "encode_base64"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_md5_bin); - lua_setfield(L, -2, "md5_bin"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_md5); - lua_setfield(L, -2, "md5"); - -#if (NGX_HAVE_SHA1) - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_sha1_bin); - lua_setfield(L, -2, "sha1_bin"); -#endif - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_crc32_short); lua_setfield(L, -2, "crc32_short"); @@ -104,75 +64,6 @@ ngx_[% subsys %]_lua_inject_string_api(lua_State *L) } -static int -ngx_[% subsys %]_lua_ngx_escape_uri(lua_State *L) -{ - size_t len, dlen; - uintptr_t escape; - u_char *src, *dst; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_isnil(L, 1)) { - lua_pushliteral(L, ""); - return 1; - } - - src = (u_char *) luaL_checklstring(L, 1, &len); - - if (len == 0) { - return 1; - } - - escape = 2 * ngx_[% subsys %]_lua_escape_uri(NULL, src, len, - NGX_ESCAPE_URI_COMPONENT); - - if (escape) { - dlen = escape + len; - dst = lua_newuserdata(L, dlen); - ngx_[% subsys %]_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI_COMPONENT); - lua_pushlstring(L, (char *) dst, dlen); - } - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_unescape_uri(lua_State *L) -{ - size_t len, dlen; - u_char *p; - u_char *src, *dst; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_isnil(L, 1)) { - lua_pushliteral(L, ""); - return 1; - } - - src = (u_char *) luaL_checklstring(L, 1, &len); - - /* the unescaped string can only be smaller */ - dlen = len; - - p = lua_newuserdata(L, dlen); - - dst = p; - - ngx_[% subsys %]_lua_unescape_uri(&dst, &src, len, NGX_UNESCAPE_URI_COMPONENT); - - lua_pushlstring(L, (char *) p, dst - p); - - return 1; -} - - static int ngx_[% subsys %]_lua_ngx_quote_sql_str(lua_State *L) { @@ -320,138 +211,6 @@ ngx_[% subsys %]_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size) } -static int -ngx_[% subsys %]_lua_ngx_md5(lua_State *L) -{ - u_char *src; - size_t slen; - - ngx_md5_t md5; - u_char md5_buf[MD5_DIGEST_LENGTH]; - u_char hex_buf[2 * sizeof(md5_buf)]; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_isnil(L, 1)) { - src = (u_char *) ""; - slen = 0; - - } else { - src = (u_char *) luaL_checklstring(L, 1, &slen); - } - - ngx_md5_init(&md5); - ngx_md5_update(&md5, src, slen); - ngx_md5_final(md5_buf, &md5); - - ngx_hex_dump(hex_buf, md5_buf, sizeof(md5_buf)); - - lua_pushlstring(L, (char *) hex_buf, sizeof(hex_buf)); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_md5_bin(lua_State *L) -{ - u_char *src; - size_t slen; - - ngx_md5_t md5; - u_char md5_buf[MD5_DIGEST_LENGTH]; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_isnil(L, 1)) { - src = (u_char *) ""; - slen = 0; - - } else { - src = (u_char *) luaL_checklstring(L, 1, &slen); - } - - dd("slen: %d", (int) slen); - - ngx_md5_init(&md5); - ngx_md5_update(&md5, src, slen); - ngx_md5_final(md5_buf, &md5); - - lua_pushlstring(L, (char *) md5_buf, sizeof(md5_buf)); - - return 1; -} - - -#if (NGX_HAVE_SHA1) -static int -ngx_[% subsys %]_lua_ngx_sha1_bin(lua_State *L) -{ - u_char *src; - size_t slen; - - ngx_sha1_t sha; - u_char sha_buf[SHA_DIGEST_LENGTH]; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_isnil(L, 1)) { - src = (u_char *) ""; - slen = 0; - - } else { - src = (u_char *) luaL_checklstring(L, 1, &slen); - } - - dd("slen: %d", (int) slen); - - ngx_sha1_init(&sha); - ngx_sha1_update(&sha, src, slen); - ngx_sha1_final(sha_buf, &sha); - - lua_pushlstring(L, (char *) sha_buf, sizeof(sha_buf)); - - return 1; -} -#endif - - -static int -ngx_[% subsys %]_lua_ngx_decode_base64(lua_State *L) -{ - ngx_str_t p, src; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - if (lua_type(L, 1) != LUA_TSTRING) { - return luaL_error(L, "string argument only"); - } - - src.data = (u_char *) luaL_checklstring(L, 1, &src.len); - - p.len = ngx_base64_decoded_length(src.len); - - p.data = lua_newuserdata(L, p.len); - - if (ngx_decode_base64(&p, &src) == NGX_OK) { - lua_pushlstring(L, (char *) p.data, p.len); - - } else { - lua_pushnil(L); - } - - return 1; -} - - static void ngx_[% subsys %]_lua_encode_base64(ngx_str_t *dst, ngx_str_t *src, int no_padding) { @@ -497,51 +256,6 @@ ngx_[% subsys %]_lua_encode_base64(ngx_str_t *dst, ngx_str_t *src, int no_paddin } -static size_t -ngx_[% subsys %]_lua_base64_encoded_length(size_t n, int no_padding) -{ - return no_padding ? (n * 8 + 5) / 6 : ngx_base64_encoded_length(n); -} - - -static int -ngx_[% subsys %]_lua_ngx_encode_base64(lua_State *L) -{ - int n; - int no_padding = 0; - ngx_str_t p, src; - - n = lua_gettop(L); - if (n != 1 && n != 2) { - return luaL_error(L, "expecting one or two arguments"); - } - - if (lua_isnil(L, 1)) { - src.data = (u_char *) ""; - src.len = 0; - - } else { - src.data = (u_char *) luaL_checklstring(L, 1, &src.len); - } - - if (n == 2) { - /* get the 2nd optional argument */ - luaL_checktype(L, 2, LUA_TBOOLEAN); - no_padding = lua_toboolean(L, 2); - } - - p.len = ngx_[% subsys %]_lua_base64_encoded_length(src.len, no_padding); - - p.data = lua_newuserdata(L, p.len); - - ngx_[% subsys %]_lua_encode_base64(&p, &src, no_padding); - - lua_pushlstring(L, (char *) p.data, p.len); - - return 1; -} - - static int ngx_[% subsys %]_lua_ngx_crc32_short(lua_State *L) { @@ -658,7 +372,6 @@ ngx_[% subsys %]_lua_ngx_hmac_sha1(lua_State *L) #endif -#ifndef NGX_LUA_NO_FFI_API void ngx_[% subsys %]_lua_ffi_md5_bin(const u_char *src, size_t len, u_char *dst) { @@ -764,6 +477,22 @@ ngx_[% subsys %]_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) NGX_ESCAPE_URI_COMPONENT); } -#endif + +[% IF http_subsys %] +void +ngx_[% subsys %]_lua_ffi_str_replace_char(u_char *buf, size_t len, + const u_char find, const u_char replace) +{ + while (len) { + if (*buf == find) { + *buf = replace; + } + + buf++; + len--; + } +} +[% END %] + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_time.c.tt2 b/src/subsys/ngx_subsys_lua_time.c.tt2 index 601ee9e..684509c 100644 --- a/src/subsys/ngx_subsys_lua_time.c.tt2 +++ b/src/subsys/ngx_subsys_lua_time.c.tt2 @@ -11,253 +11,7 @@ #include "ddebug.h" -#include "ngx_[% subsys %]_lua_time.h" -#include "ngx_[% subsys %]_lua_util.h" - - -static int ngx_[% subsys %]_lua_ngx_today(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_time(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_now(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_localtime(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_utctime(lua_State *L); -[% IF http_subsys %] -static int ngx_[% subsys %]_lua_ngx_cookie_time(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_http_time(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_parse_http_time(lua_State *L); -[% END %] -static int ngx_[% subsys %]_lua_ngx_update_time(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_req_start_time(lua_State *L); - - -static int -ngx_[% subsys %]_lua_ngx_today(lua_State *L) -{ - time_t now; - ngx_tm_t tm; - u_char buf[sizeof("2010-11-19") - 1]; - - now = ngx_time(); - 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); - - lua_pushlstring(L, (char *) buf, sizeof(buf)); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_localtime(lua_State *L) -{ - ngx_tm_t tm; - - u_char buf[sizeof("2010-11-19 20:56:31") - 1]; - - 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); - - lua_pushlstring(L, (char *) buf, sizeof(buf)); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_time(lua_State *L) -{ - lua_pushnumber(L, (lua_Number) ngx_time()); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_now(lua_State *L) -{ - ngx_time_t *tp; - - tp = ngx_timeofday(); - - lua_pushnumber(L, (lua_Number) (tp->sec + tp->msec / 1000.0L)); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_update_time(lua_State *L) -{ - ngx_time_update(); - return 0; -} - - -static int -ngx_[% subsys %]_lua_ngx_utctime(lua_State *L) -{ - 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); - - lua_pushlstring(L, (char *) buf, sizeof(buf)); - - return 1; -} - - -[% IF http_subsys %] -static int -ngx_[% subsys %]_lua_ngx_cookie_time(lua_State *L) -{ - time_t t; - u_char *p; - - u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1]; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - t = (time_t) luaL_checknumber(L, 1); - - p = buf; - p = ngx_http_cookie_time(p, t); - - lua_pushlstring(L, (char *) buf, p - buf); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_http_time(lua_State *L) -{ - time_t t; - u_char *p; - - u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1]; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - t = (time_t) luaL_checknumber(L, 1); - - p = buf; - p = ngx_http_time(p, t); - - lua_pushlstring(L, (char *) buf, p - buf); - - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_parse_http_time(lua_State *L) -{ - u_char *p; - size_t len; - time_t time; - - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); - } - - p = (u_char *) luaL_checklstring(L, 1, &len); - - time = ngx_http_parse_time(p, len); - if (time == NGX_ERROR) { - lua_pushnil(L); - return 1; - } - - lua_pushnumber(L, (lua_Number) time); - - return 1; -} -[% END # http %] - - -static int -ngx_[% subsys %]_lua_ngx_req_start_time(lua_State *L) -{ - [% req_type %] *r; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request found"); - } - -[% IF http_subsys %] - lua_pushnumber(L, (lua_Number) (r->start_sec + r->start_msec / 1000.0L)); -[% ELSIF stream_subsys %] - lua_pushnumber(L, (lua_Number) (r->session->start_sec - + r->session->start_msec / 1000.0L)); -[% END %] - - return 1; -} - - -void -ngx_[% subsys %]_lua_inject_time_api(lua_State *L) -{ - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_utctime); - lua_setfield(L, -2, "utctime"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_time); - lua_setfield(L, -2, "get_now_ts"); /* deprecated */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_localtime); - lua_setfield(L, -2, "get_now"); /* deprecated */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_localtime); - lua_setfield(L, -2, "localtime"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_time); - lua_setfield(L, -2, "time"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_now); - lua_setfield(L, -2, "now"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_update_time); - lua_setfield(L, -2, "update_time"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_today); - lua_setfield(L, -2, "get_today"); /* deprecated */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_today); - lua_setfield(L, -2, "today"); - -[% IF http_subsys %] - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_cookie_time); - lua_setfield(L, -2, "cookie_time"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_http_time); - lua_setfield(L, -2, "http_time"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_parse_http_time); - lua_setfield(L, -2, "parse_http_time"); -[% END %] -} - - -void -ngx_[% subsys %]_lua_inject_req_time_api(lua_State *L) -{ - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_req_start_time); - lua_setfield(L, -2, "start_time"); -} +#include "ngx_[% subsys %]_lua_common.h" double @@ -359,7 +113,7 @@ ngx_[% subsys %]_lua_ffi_parse_http_time(const u_char *str, size_t len, /* ngx_http_parse_time doesn't modify 'str' actually */ *time = ngx_http_parse_time((u_char *) str, len); } +[% END # http %] -[% END # http %] /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_time.h.tt2 b/src/subsys/ngx_subsys_lua_time.h.tt2 deleted file mode 100644 index ab66d32..0000000 --- a/src/subsys/ngx_subsys_lua_time.h.tt2 +++ /dev/null @@ -1,21 +0,0 @@ - -/* - * Copyright (C) Xiaozhe Wang (chaoslawful) - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef _NGX_[% SUBSYS %]_LUA_TIME_H_INCLUDED_ -#define _NGX_[% SUBSYS %]_LUA_TIME_H_INCLUDED_ - - -#include "ngx_[% subsys %]_lua_common.h" - - -void ngx_[% subsys %]_lua_inject_time_api(lua_State *L); -void ngx_[% subsys %]_lua_inject_req_time_api(lua_State *L); - - -#endif /* _NGX_[% SUBSYS %]_LUA_TIME_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_timer.c.tt2 b/src/subsys/ngx_subsys_lua_timer.c.tt2 index 38ed1f2..5172690 100644 --- a/src/subsys/ngx_subsys_lua_timer.c.tt2 +++ b/src/subsys/ngx_subsys_lua_timer.c.tt2 @@ -16,6 +16,9 @@ #include "ngx_[% subsys %]_lua_probe.h" +#define NGX_[% SUBSYS %]_LUA_TIMER_ERRBUF_SIZE 128 + + typedef struct { void **main_conf; void **srv_conf; @@ -363,6 +366,10 @@ ngx_[% subsys %]_lua_ngx_timer_helper(lua_State *L, int every) ngx_add_timer(ev, delay); + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]created timer (co: %p delay: %M ms)", + tctx->co, delay); + lua_pushinteger(L, 1); return 1; @@ -523,6 +530,10 @@ ngx_[% subsys %]_lua_timer_copy(ngx_[% subsys %]_lua_timer_ctx_t *old_tctx) ngx_add_timer(ev, tctx->delay); + ngx_log_debug2(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, + "[% log_prefix %]created next timer (co: %p delay: %M ms)", + tctx->co, tctx->delay); + return NGX_OK; nomem: @@ -557,29 +568,36 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) lua_State *L; ngx_int_t rc; ngx_connection_t *c = NULL; - [% req_type %] *r = NULL; - ngx_[% subsys %]_lua_ctx_t *ctx; - ngx_[% req_subsys %]_cleanup_t *cln; ngx_pool_cleanup_t *pcln; + [% req_type %] *r = NULL; + ngx_[% req_subsys %]_cleanup_t *cln; + ngx_[% subsys %]_lua_ctx_t *ctx; ngx_[% subsys %]_lua_timer_ctx_t tctx; ngx_[% subsys %]_lua_main_conf_t *lmcf; [% IF http_subsys %] ngx_http_core_loc_conf_t *clcf; + [% ELSIF stream_subsys %] ngx_stream_core_srv_conf_t *clcf; -[% END %] -[% IF stream_subsys %] ngx_stream_session_t *s; [% END %] + lua_Debug ar; + u_char *p; + u_char errbuf[NGX_[% SUBSYS %]_LUA_TIMER_ERRBUF_SIZE]; + const char *source; + const char *errmsg; + ngx_log_debug0(NGX_LOG_DEBUG_[% SUBSYS %], ngx_cycle->log, 0, "[% log_prefix %]lua ngx.timer expired"); ngx_memcpy(&tctx, ev->data, sizeof(ngx_[% subsys %]_lua_timer_ctx_t)); ngx_free(ev); + ngx_[% subsys %]_lua_assert(tctx.co_ref && tctx.co); + lmcf = tctx.lmcf; lmcf->pending_timers--; @@ -594,19 +612,22 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) } if (lmcf->running_timers >= lmcf->max_running_timers) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + p = ngx_snprintf(errbuf, NGX_[% SUBSYS %]_LUA_TIMER_ERRBUF_SIZE - 1, [% IF http_subsys %] - "%i lua_max_running_timers are not enough", + "%i lua_max_running_timers are not enough", [% ELSIF stream_subsys %] - "stream lua: %i lua_max_running_timers are not enough", + "stream lua: %i lua_max_running_timers are not enough", [% END %] - lmcf->max_running_timers); + lmcf->max_running_timers); + *p = '\0'; + errmsg = (const char *) errbuf; goto failed; } c = ngx_[% subsys %]_lua_create_fake_connection(tctx.pool); if (c == NULL) { + errmsg = "could not create fake connection"; goto failed; } @@ -619,13 +640,14 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) [% IF stream_subsys %] s = ngx_stream_lua_create_fake_session(c); if (s == NULL) { + errmsg = "could not create fake session"; goto failed; } -[% END %] -[% IF http_subsys %] +[% ELSIF http_subsys %] r = ngx_http_lua_create_fake_request(c); if (r == NULL) { + errmsg = "could not create fake request"; goto failed; } [% END %] @@ -644,10 +666,7 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) clcf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); [% END %] -#if defined(nginx_version) && nginx_version >= 1003014 - -# if nginx_version >= 1009000 - +#if defined(nginx_version) && nginx_version >= 1009000 [% IF http_subsys %] ngx_set_connection_log(r->connection, clcf->error_log); @@ -655,22 +674,10 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) ngx_set_connection_log(s->connection, clcf->error_log); [% END %] -# else - +#else [% IF http_subsys %] ngx_http_set_connection_log(r->connection, clcf->error_log); [% END %] - -# endif - -#else - - 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; - } - #endif dd("lmcf: %p", lmcf); @@ -682,6 +689,7 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) ctx = ngx_stream_lua_create_ctx(s); [% END %] if (ctx == NULL) { + errmsg = "could not create ctx"; goto failed; } @@ -694,6 +702,7 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { + errmsg = "could not add vm cleanup"; goto failed; } @@ -707,6 +716,7 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) cln = ngx_[% req_subsys %]_cleanup_add(r, 0); if (cln == NULL) { + errmsg = "could not add request cleanup"; goto failed; } @@ -763,14 +773,26 @@ ngx_[% subsys %]_lua_timer_handler(ngx_event_t *ev) failed: - if (tctx.co_ref && tctx.co) { - lua_pushlightuserdata(tctx.co, ngx_[% subsys %]_lua_lightudata_mask( - coroutines_key)); - lua_rawget(tctx.co, LUA_REGISTRYINDEX); - luaL_unref(tctx.co, -1, tctx.co_ref); - lua_settop(tctx.co, 0); + /* co stack: func [args] */ + lua_getinfo(tctx.co, ">Sf", &ar); + + source = ar.source; + + if (source == NULL) { + source = "(unknown)"; } + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "[% log_prefix %]lua failed to run timer with function " + "defined at %s:%d: %s", + source, ar.linedefined, errmsg); + + lua_pushlightuserdata(tctx.co, ngx_[% subsys %]_lua_lightudata_mask( + coroutines_key)); + lua_rawget(tctx.co, LUA_REGISTRYINDEX); + luaL_unref(tctx.co, -1, tctx.co_ref); + lua_settop(tctx.co, 0); + if (tctx.vm_state) { ngx_[% subsys %]_lua_cleanup_vm(tctx.vm_state); } diff --git a/src/subsys/ngx_subsys_lua_uthread.c.tt2 b/src/subsys/ngx_subsys_lua_uthread.c.tt2 index 8607d9f..88e5ec6 100644 --- a/src/subsys/ngx_subsys_lua_uthread.c.tt2 +++ b/src/subsys/ngx_subsys_lua_uthread.c.tt2 @@ -130,6 +130,7 @@ ngx_[% subsys %]_lua_uthread_wait(lua_State *L) [% IF http_subsys %] | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH [% ELSIF stream_subsys %] | NGX_STREAM_LUA_CONTEXT_PREREAD @@ -236,6 +237,7 @@ ngx_[% subsys %]_lua_uthread_kill(lua_State *L) [% IF http_subsys %] | NGX_[% SUBSYS %]_LUA_CONTEXT_REWRITE | NGX_[% SUBSYS %]_LUA_CONTEXT_ACCESS + | NGX_[% SUBSYS %]_LUA_CONTEXT_SSL_SESS_FETCH [% ELSIF stream_subsys %] | NGX_STREAM_LUA_CONTEXT_PREREAD diff --git a/src/subsys/ngx_subsys_lua_util.c.tt2 b/src/subsys/ngx_subsys_lua_util.c.tt2 index dcadad6..234cadf 100644 --- a/src/subsys/ngx_subsys_lua_util.c.tt2 +++ b/src/subsys/ngx_subsys_lua_util.c.tt2 @@ -16,13 +16,10 @@ #include "ngx_[% subsys %]_lua_util.h" #include "ngx_[% subsys %]_lua_exception.h" #include "ngx_[% subsys %]_lua_pcrefix.h" -#include "ngx_[% subsys %]_lua_regex.h" #include "ngx_[% subsys %]_lua_args.h" #include "ngx_[% subsys %]_lua_output.h" -#include "ngx_[% subsys %]_lua_time.h" #include "ngx_[% subsys %]_lua_control.h" #include "ngx_[% subsys %]_lua_log.h" -#include "ngx_[% subsys %]_lua_variable.h" #include "ngx_[% subsys %]_lua_string.h" #include "ngx_[% subsys %]_lua_misc.h" #include "ngx_[% subsys %]_lua_consts.h" @@ -31,13 +28,11 @@ #include "ngx_[% subsys %]_lua_socket_tcp.h" #include "ngx_[% subsys %]_lua_socket_udp.h" #include "ngx_[% subsys %]_lua_sleep.h" -#include "ngx_[% subsys %]_lua_phase.h" #include "ngx_[% subsys %]_lua_probe.h" #include "ngx_[% subsys %]_lua_uthread.h" #include "ngx_[% subsys %]_lua_contentby.h" #include "ngx_[% subsys %]_lua_timer.h" #include "ngx_[% subsys %]_lua_config.h" -#include "ngx_[% subsys %]_lua_worker.h" #include "ngx_[% subsys %]_lua_ssl.h" @@ -53,7 +48,9 @@ #include "ngx_[% subsys %]_lua_logby.h" #include "ngx_[% subsys %]_lua_ndk.h" #include "ngx_[% subsys %]_lua_subrequest.h" -#include "ngx_[% subsys %]_lua_req_method.h" + +[% ELSIF stream_subsys %] +#include "ngx_[% subsys %]_lua_phase.h" [% END %] @@ -120,6 +117,10 @@ static void ngx_[% subsys %]_lua_inject_arg_api(lua_State *L); static void ngx_[% subsys %]_lua_init_registry(lua_State *L, ngx_log_t *log); static void ngx_[% subsys %]_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log); +#ifdef OPENRESTY_LUAJIT +static void ngx_[% subsys %]_lua_inject_global_write_guard(lua_State *L, + ngx_log_t *log); +#endif static void ngx_[% subsys %]_lua_set_path(ngx_cycle_t *cycle, lua_State *L, int tab_idx, const char *fieldname, const char *path, const char *default_path, ngx_log_t *log); @@ -277,7 +278,6 @@ ngx_[% subsys %]_lua_new_state(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pushliteral(L, LUA_DEFAULT_PATH ";"); /* package default */ lua_getfield(L, -2, "path"); /* package default old */ - old_path = lua_tolstring(L, -1, &old_path_len); lua_concat(L, 2); /* package new */ lua_setfield(L, -2, "path"); /* package */ #endif @@ -449,7 +449,9 @@ ngx_[% subsys %]_lua_send_header_if_needed([% req_type %] *r, r->headers_out.status = NGX_HTTP_OK; } - if (!ctx->headers_set && ngx_[% subsys %]_lua_set_content_type(r) != NGX_OK) { + if (!ctx->mime_set + && ngx_[% subsys %]_lua_set_content_type(r, ctx) != NGX_OK) + { return NGX_ERROR; } @@ -549,16 +551,6 @@ ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, } } -#if defined(nginx_version) && nginx_version <= 8004 - - /* earlier versions of nginx does not allow subrequests - to send last_buf themselves */ - if (r != r->main) { - return NGX_OK; - } - -#endif - ctx->eof = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -663,11 +655,7 @@ ngx_[% subsys %]_lua_output_filter([% req_type %] *r, ngx_chain_t *in) ctx = ngx_[% req_subsys %]_get_module_ctx(r, ngx_[% subsys %]_lua_module); -#if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, -#else - ngx_chain_update_chains( -#endif &ctx->free_bufs, &ctx->busy_bufs, &in, (ngx_buf_tag_t) &ngx_[% subsys %]_lua_module); @@ -780,7 +768,7 @@ static void ngx_[% subsys %]_lua_inject_ngx_api(lua_State *L, ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log) { - lua_createtable(L, 0 /* narr */, 117 /* nrec */); /* ngx.* */ + lua_createtable(L, 0 /* narr */, 113 /* nrec */); /* ngx.* */ lua_pushcfunction(L, ngx_[% subsys %]_lua_get_raw_phase_context); lua_setfield(L, -2, "_phase_ctx"); @@ -795,7 +783,6 @@ ngx_[% subsys %]_lua_inject_ngx_api(lua_State *L, ngx_[% subsys %]_lua_main_conf ngx_[% subsys %]_lua_inject_log_api(L); ngx_[% subsys %]_lua_inject_output_api(L); - ngx_[% subsys %]_lua_inject_time_api(L); ngx_[% subsys %]_lua_inject_string_api(L); ngx_[% subsys %]_lua_inject_control_api(log, L); @@ -804,11 +791,9 @@ ngx_[% subsys %]_lua_inject_ngx_api(lua_State *L, ngx_[% subsys %]_lua_main_conf [% END %] ngx_[% subsys %]_lua_inject_sleep_api(L); +[% IF stream_subsys %] ngx_[% subsys %]_lua_inject_phase_api(L); - -#if (NGX_PCRE) - ngx_[% subsys %]_lua_inject_regex_api(L); -#endif +[% END %] ngx_[% subsys %]_lua_inject_req_api(log, L); @@ -817,16 +802,12 @@ ngx_[% subsys %]_lua_inject_ngx_api(lua_State *L, ngx_[% subsys %]_lua_main_conf ngx_[% subsys %]_lua_create_headers_metatable(log, L); [% END %] - ngx_[% subsys %]_lua_inject_variable_api(L); ngx_[% subsys %]_lua_inject_shdict_api(lmcf, L); ngx_[% subsys %]_lua_inject_socket_tcp_api(log, L); ngx_[% subsys %]_lua_inject_socket_udp_api(log, L); ngx_[% subsys %]_lua_inject_uthread_api(log, L); ngx_[% subsys %]_lua_inject_timer_api(L); ngx_[% subsys %]_lua_inject_config_api(L); - ngx_[% subsys %]_lua_inject_worker_api(L); - - ngx_[% subsys %]_lua_inject_misc_api(L); lua_getglobal(L, "package"); /* ngx package */ lua_getfield(L, -1, "loaded"); /* ngx package loaded */ @@ -837,53 +818,55 @@ ngx_[% subsys %]_lua_inject_ngx_api(lua_State *L, ngx_[% subsys %]_lua_main_conf lua_setglobal(L, "ngx"); ngx_[% subsys %]_lua_inject_coroutine_api(log, L); +} #ifdef OPENRESTY_LUAJIT - { - int rc; - - const char buf[] = - "local ngx_log = ngx.log\n" - "local ngx_WARN = ngx.WARN\n" - "local tostring = tostring\n" - "local ngx_get_phase = ngx.get_phase\n" - "local traceback = require 'debug'.traceback\n" - "local function newindex(table, key, value)\n" - "rawset(table, key, value)\n" - "local phase = ngx_get_phase()\n" - "if phase == 'init_worker' or phase == 'init' then\n" - "return\n" - "end\n" - "ngx_log(ngx_WARN, 'writing a global lua variable " - "(\\'', tostring(key), '\\') which may lead to " - "race conditions between concurrent requests, so " - "prefer the use of \\'local\\' variables', " - "traceback('', 2))\n" +static void +ngx_[% subsys %]_lua_inject_global_write_guard(lua_State *L, ngx_log_t *log) +{ + int rc; + + const char buf[] = + "local ngx_log = ngx.log\n" + "local ngx_WARN = ngx.WARN\n" + "local tostring = tostring\n" + "local ngx_get_phase = ngx.get_phase\n" + "local traceback = require 'debug'.traceback\n" + "local function newindex(table, key, value)\n" + "rawset(table, key, value)\n" + "local phase = ngx_get_phase()\n" + "if phase == 'init_worker' or phase == 'init' then\n" + "return\n" "end\n" - "setmetatable(_G, { __newindex = newindex })\n" - ; - - rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); + "ngx_log(ngx_WARN, 'writing a global Lua variable " + "(\\'', tostring(key), '\\') which may lead to " + "race conditions between concurrent requests, so " + "prefer the use of \\'local\\' variables', " + "traceback('', 2))\n" + "end\n" + "setmetatable(_G, { __newindex = newindex })\n" + ; + + rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=_G write guard"); + + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to load Lua code (%i): %s", + rc, lua_tostring(L, -1)); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to load Lua code (%i): %s", - rc, lua_tostring(L, -1)); - - lua_pop(L, 1); - return; - } + lua_pop(L, 1); + return; + } - rc = lua_pcall(L, 0, 0, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "failed to run Lua code (%i): %s", - rc, lua_tostring(L, -1)); - lua_pop(L, 1); - } + rc = lua_pcall(L, 0, 0, 0); + if (rc != 0) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "failed to run Lua code (%i): %s", + rc, lua_tostring(L, -1)); + lua_pop(L, 1); } -#endif } +#endif void @@ -1005,9 +988,7 @@ ngx_[% subsys %]_lua_generic_phase_post_read([% req_type %] *r) ctx->read_body_done = 1; -#if defined(nginx_version) && nginx_version >= 8011 r->main->count--; -#endif if (ctx->waiting_more_body) { ctx->waiting_more_body = 0; @@ -1109,10 +1090,16 @@ ngx_[% subsys %]_lua_run_thread(lua_State *L, [% req_type %] *r, /* set Lua VM panic handler */ lua_atpanic(L, ngx_[% subsys %]_lua_atpanic); - dd("ctx = %p", ctx); - NGX_LUA_EXCEPTION_TRY { + /* + * silence a -Werror=clobbered warning with gcc 5.4 + * due to above setjmp + */ + err = NULL; + msg = NULL; + trace = NULL; + if (ctx->cur_co_ctx->thread_spawn_yielded) { ngx_[% subsys %]_lua_probe_info("thread spawn yielded"); @@ -1122,19 +1109,15 @@ ngx_[% subsys %]_lua_run_thread(lua_State *L, [% req_type %] *r, for ( ;; ) { - dd("calling lua_resume: vm %p, nret %d", ctx->cur_co_ctx->co, - (int) nrets); + dd("ctx: %p, co: %p, co status: %d, co is_wrap: %d", + ctx, ctx->cur_co_ctx->co, ctx->cur_co_ctx->co_status, + ctx->cur_co_ctx->is_wrap); #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_[% subsys %]_lua_pcre_malloc_init(r->pool); #endif - /* run code */ - dd("ctx: %p", ctx); - dd("cur co: %p", ctx->cur_co_ctx->co); - dd("cur co status: %d", ctx->cur_co_ctx->co_status); - orig_coctx = ctx->cur_co_ctx; #ifdef NGX_LUA_USE_ASSERT @@ -1146,10 +1129,19 @@ ngx_[% subsys %]_lua_run_thread(lua_State *L, [% req_type %] *r, #if DDEBUG if (lua_gettop(orig_coctx->co) > 0) { - dd("top elem: %s", luaL_typename(orig_coctx->co, -1)); + dd("co top elem: %s", luaL_typename(orig_coctx->co, -1)); + } + + if (orig_coctx->propagate_error) { + dd("co propagate_error: %d", orig_coctx->propagate_error); } #endif + if (orig_coctx->propagate_error) { + orig_coctx->propagate_error = 0; + goto propagate_error; + } + ngx_[% subsys %]_lua_assert(orig_coctx->co_top + nrets == lua_gettop(orig_coctx->co)); @@ -1299,12 +1291,6 @@ ngx_[% subsys %]_lua_run_thread(lua_State *L, [% req_type %] *r, next_coctx = ctx->cur_co_ctx->parent_co_ctx; next_co = next_coctx->co; - /* - * prepare return values for coroutine.resume - * (true plus any retvals) - */ - 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); @@ -1313,7 +1299,14 @@ ngx_[% subsys %]_lua_run_thread(lua_State *L, [% req_type %] *r, #endif } - nrets++; /* add the true boolean value */ + if (!ctx->cur_co_ctx->is_wrap) { + /* prepare return values for coroutine.resume + * (true plus any retvals) + */ + lua_pushboolean(next_co, 1); + lua_insert(next_co, 1); + nrets++; /* add the true boolean value */ + } ctx->cur_co_ctx = next_coctx; @@ -1424,12 +1417,6 @@ user_co_done: next_co = next_coctx->co; - /* - * ended successful, coroutine.resume returns true plus - * any return values - */ - lua_pushboolean(next_co, success); - if (nrets) { lua_xmove(ctx->cur_co_ctx->co, next_co, nrets); } @@ -1439,7 +1426,15 @@ user_co_done: ctx->uthreads--; } - nrets++; + if (!ctx->cur_co_ctx->is_wrap) { + /* ended successfully, coroutine.resume returns true plus + * any return values + */ + lua_pushboolean(next_co, success); + lua_insert(next_co, 1); + nrets++; + } + ctx->cur_co_ctx = next_coctx; ngx_[% subsys %]_lua_probe_info("set parent running"); @@ -1477,25 +1472,34 @@ user_co_done: 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); - - } else { - msg = "unknown reason"; - } - ngx_[% subsys %]_lua_cleanup_pending_operation(ctx->cur_co_ctx); ngx_[% subsys %]_lua_probe_coroutine_done(r, ctx->cur_co_ctx->co, 0); ctx->cur_co_ctx->co_status = NGX_[% SUBSYS %]_LUA_CO_DEAD; - ngx_[% subsys %]_lua_thread_traceback(L, ctx->cur_co_ctx->co, - ctx->cur_co_ctx); - trace = lua_tostring(L, -1); + if (orig_coctx->is_uthread + || orig_coctx->is_wrap + || ngx_[% subsys %]_lua_is_entry_thread(ctx)) + { + ngx_[% subsys %]_lua_thread_traceback(L, orig_coctx->co, + orig_coctx); + trace = lua_tostring(L, -1); + + if (lua_isstring(orig_coctx->co, -1)) { + msg = lua_tostring(orig_coctx->co, -1); + dd("user custom error msg: %s", msg); + + } else { + msg = "unknown reason"; + } + } + +propagate_error: if (ctx->cur_co_ctx->is_uthread) { + ngx_[% subsys %]_lua_assert(err != NULL && msg != NULL + && trace != NULL); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[% log_prefix %]lua user thread aborted: %s: %s\n%s", @@ -1546,6 +1550,9 @@ user_co_done: } if (ngx_[% subsys %]_lua_is_entry_thread(ctx)) { + ngx_[% subsys %]_lua_assert(err != NULL && msg != NULL + && trace != NULL); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua entry thread aborted: %s: %s\n%s", err, msg, trace); @@ -1592,19 +1599,25 @@ user_co_done: next_coctx->co_status = NGX_[% SUBSYS %]_LUA_CO_RUNNING; + ctx->cur_co_ctx = next_coctx; + + if (orig_coctx->is_wrap) { + /* + * coroutine.wrap propagates errors + * to its parent coroutine + */ + next_coctx->propagate_error = 1; + continue; + } + /* * ended with error, coroutine.resume returns false plus * err msg */ lua_pushboolean(next_co, 0); - lua_xmove(ctx->cur_co_ctx->co, next_co, 1); + lua_xmove(orig_coctx->co, next_co, 1); nrets = 2; - 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); - /* try resuming on the new coroutine again */ continue; } @@ -2302,16 +2315,15 @@ done: static int -ngx_[% subsys%]_lua_req_socket(lua_State *L) +ngx_[% subsys %]_lua_req_socket(lua_State *L) { -[% IF stream_subsys %] - ngx_stream_lua_request_t *r; - ngx_stream_lua_ctx_t *ctx; -[% END %] - [% IF http_subsys %] return ngx_http_lua_req_socket_tcp(L); + [% ELSIF stream_subsys %] + ngx_stream_lua_request_t *r; + ngx_stream_lua_ctx_t *ctx; + r = ngx_stream_lua_get_req(L); ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); @@ -2331,12 +2343,13 @@ ngx_[% subsys%]_lua_req_socket(lua_State *L) /* shouldn't happen */ ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, - "unexpected connection type: %d", r->connection->type); -[% END %] + "[% log_prefix %]unexpected connection type: %d", + r->connection->type); ngx_stream_lua_assert(0); return luaL_error(L, "unexpected connection type"); +[% END %] } @@ -2345,21 +2358,22 @@ ngx_[% subsys %]_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 24 /* nrec */); /* .req */ +[% IF stream_subsys %] + lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* .req */ - lua_pushcfunction(L, ngx_[% subsys %]_lua_req_socket); - lua_setfield(L, -2, "socket"); +[% ELSIF http_subsys %] + lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */ -[% IF http_subsys %] ngx_[% subsys %]_lua_inject_req_header_api(L); ngx_[% subsys %]_lua_inject_req_uri_api(log, L); ngx_[% subsys %]_lua_inject_req_args_api(L); ngx_[% subsys %]_lua_inject_req_body_api(L); - ngx_[% subsys %]_lua_inject_req_method_api(L); - ngx_[% subsys %]_lua_inject_req_time_api(L); ngx_[% subsys %]_lua_inject_req_misc_api(L); [% END %] + lua_pushcfunction(L, ngx_[% subsys %]_lua_req_socket); + lua_setfield(L, -2, "socket"); + lua_setfield(L, -2, "req"); } @@ -2944,9 +2958,7 @@ done: of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); -#if defined(nginx_version) && nginx_version >= 1000001 of->fs_size = ngx_file_fs_size(&fi); -#endif of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); @@ -4054,9 +4066,10 @@ ngx_[% subsys %]_lua_close_fake_connection(ngx_connection_t *c) } -lua_State * -ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, - ngx_pool_t *pool, ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log, +ngx_int_t +ngx_[% subsys %]_lua_init_vm(lua_State **new_vm, lua_State *parent_vm, + ngx_cycle_t *cycle, ngx_pool_t *pool, + ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln) { int rc; @@ -4069,13 +4082,13 @@ ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, cln = ngx_pool_cleanup_add(pool, 0); if (cln == NULL) { - return NULL; + return NGX_ERROR; } /* create new Lua VM instance */ L = ngx_[% subsys %]_lua_new_state(parent_vm, cycle, lmcf, log); if (L == NULL) { - return NULL; + return NGX_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_[% SUBSYS %], log, 0, "lua initialize the " @@ -4086,7 +4099,7 @@ ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, state = ngx_alloc(sizeof(ngx_[% subsys %]_lua_vm_state_t), log); if (state == NULL) { - return NULL; + return NGX_ERROR; } state->vm = L; state->count = 1; @@ -4119,7 +4132,8 @@ ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, for (i = 0; i < lmcf->preload_hooks->nelts; i++) { - ngx_[% subsys %]_lua_probe_register_preload_package(L, hook[i].package); + ngx_[% subsys %]_lua_probe_register_preload_package(L, + hook[i].package); lua_pushcfunction(L, hook[i].loader); lua_setfield(L, -2, (char *) hook[i].package); @@ -4128,22 +4142,21 @@ ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, lua_pop(L, 2); } - if (lmcf->load_resty_core) { - lua_getglobal(L, "require"); - lua_pushstring(L, "resty.core"); + *new_vm = L; - rc = lua_pcall(L, 1, 1, 0); - if (rc != 0) { - ngx_log_error(NGX_LOG_ERR, log, 0, - "lua_load_resty_core failed to load the resty.core " - "module from https://github.com/openresty/lua-resty" - "-core; ensure you are using an OpenResty release " - "from https://openresty.org/en/download.html " - "(rc: %i, reason: %s)", rc, lua_tostring(L, -1)); - } + lua_getglobal(L, "require"); + lua_pushstring(L, "resty.core"); + + rc = lua_pcall(L, 1, 1, 0); + if (rc != 0) { + return NGX_DECLINED; } - return L; +#ifdef OPENRESTY_LUAJIT + ngx_[% subsys %]_lua_inject_global_write_guard(L, log); +#endif + + return NGX_OK; } diff --git a/src/subsys/ngx_subsys_lua_util.h.tt2 b/src/subsys/ngx_subsys_lua_util.h.tt2 index 5c2d3f8..e9955ae 100644 --- a/src/subsys/ngx_subsys_lua_util.h.tt2 +++ b/src/subsys/ngx_subsys_lua_util.h.tt2 @@ -23,19 +23,10 @@ #endif -#ifndef NGX_LUA_NO_FFI_API -typedef struct { - int len; - /* this padding hole on 64-bit systems is expected */ - u_char *data; -} ngx_[% subsys %]_lua_ffi_str_t; - - typedef struct { ngx_[% subsys %]_lua_ffi_str_t key; ngx_[% subsys %]_lua_ffi_str_t value; } ngx_[% subsys %]_lua_ffi_table_elt_t; -#endif /* NGX_LUA_NO_FFI_API */ /* char whose address we use as the key in Lua vm registry for @@ -48,7 +39,7 @@ extern char ngx_[% subsys %]_lua_code_cache_key; /* char whose address we use as the key in Lua vm registry for - * regex cache table */ + * regex cache table */ extern char ngx_[% subsys %]_lua_regex_cache_key; /* char whose address we use as the key in Lua vm registry for @@ -75,15 +66,8 @@ extern char ngx_[% subsys %]_lua_headers_metatable_key; #ifndef NGX_HTTP_SWITCHING_PROTOCOLS #define NGX_HTTP_SWITCHING_PROTOCOLS 101 #endif -[% END %] - -#if defined(nginx_version) && nginx_version < 1000000 -#define ngx_memmove(dst, src, n) (void) memmove(dst, src, n) -#endif - -[% IF http_subsys %] #define ngx_http_lua_context_name(c) \ ((c) == NGX_HTTP_LUA_CONTEXT_SET ? "set_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_REWRITE ? "rewrite_by_lua*" \ @@ -101,6 +85,7 @@ extern char ngx_[% subsys %]_lua_headers_metatable_key; : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \ "ssl_session_fetch_by_lua*" \ : "(unknown)") + [% ELSIF stream_subsys %] #define ngx_stream_lua_context_name(c) \ ((c) == NGX_STREAM_LUA_CONTEXT_CONTENT ? "content_by_lua*" \ @@ -121,9 +106,6 @@ extern char ngx_[% subsys %]_lua_headers_metatable_key; } -[% IF http_subsys %] -#ifndef NGX_LUA_NO_FFI_API -[% END %] static ngx_inline ngx_int_t ngx_[% subsys %]_lua_ffi_check_context(ngx_[% subsys %]_lua_ctx_t *ctx, unsigned flags, u_char *err, size_t *errlen) @@ -139,9 +121,6 @@ ngx_[% subsys %]_lua_ffi_check_context(ngx_[% subsys %]_lua_ctx_t *ctx, return NGX_OK; } -[% IF http_subsys %] -#endif -[% END %] #define ngx_[% subsys %]_lua_check_fake_request(L, r) \ @@ -162,8 +141,9 @@ ngx_[% subsys %]_lua_ffi_check_context(ngx_[% subsys %]_lua_ctx_t *ctx, SSL_get_ex_data(ssl_conn, ngx_[% subsys %]_lua_ssl_ctx_index) -lua_State *ngx_[% subsys %]_lua_init_vm(lua_State *parent_vm, ngx_cycle_t *cycle, - ngx_pool_t *pool, ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log, +ngx_int_t ngx_[% subsys %]_lua_init_vm(lua_State **new_vm, lua_State *parent_vm, + ngx_cycle_t *cycle, ngx_pool_t *pool, + ngx_[% subsys %]_lua_main_conf_t *lmcf, ngx_log_t *log, ngx_pool_cleanup_t **pcln); lua_State *ngx_[% subsys %]_lua_new_thread([% req_type %] *r, lua_State *l, @@ -322,7 +302,8 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) ngx_stream_lua_create_ctx(ngx_stream_session_t *r) [% END %] { - lua_State *L; + ngx_int_t rc; + lua_State *L = NULL; ngx_[% subsys %]_lua_ctx_t *ctx; ngx_pool_cleanup_t *cln; ngx_[% subsys %]_lua_loc_conf_t *llcf; @@ -374,8 +355,8 @@ ngx_stream_lua_create_ctx(ngx_stream_session_t *r) #endif [% IF http_subsys %] - L = ngx_http_lua_init_vm(lmcf->lua, lmcf->cycle, r->pool, lmcf, - r->connection->log, &cln); + rc = ngx_http_lua_init_vm(&L, lmcf->lua, lmcf->cycle, r->pool, lmcf, + r->connection->log, &cln); [% ELSIF stream_subsys %] /* @@ -385,8 +366,8 @@ ngx_stream_lua_create_ctx(ngx_stream_session_t *r) * the correct semantics. */ - L = ngx_stream_lua_init_vm(lmcf->lua, lmcf->cycle, sreq->pool, lmcf, - r->connection->log, &cln); + rc = ngx_stream_lua_init_vm(&L, lmcf->lua, lmcf->cycle, sreq->pool, + lmcf, r->connection->log, &cln); while (cln->next != NULL) { cln = cln->next; @@ -399,11 +380,30 @@ ngx_stream_lua_create_ctx(ngx_stream_session_t *r) cln->next = NULL; [% END %] - if (L == NULL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "failed to initialize Lua VM"); - return NULL; - } + if (rc != NGX_OK) { + if (rc == NGX_DECLINED) { + ngx_[% subsys %]_lua_assert(L != NULL); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to load the 'resty.core' module " + "(https://github.com/openresty/lua-resty" + "-core); ensure you are using an OpenResty " + "release from https://openresty.org/en/" + "download.html (reason: %s)", + lua_tostring(L, -1)); + + } else { + /* rc == NGX_ERROR */ + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "failed to initialize Lua VM"); + } + + return NULL; + } + + /* rc == NGX_OK */ + + ngx_[% subsys %]_lua_assert(L != NULL); if (lmcf->init_handler) { if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) { @@ -514,10 +514,13 @@ ngx_[% subsys %]_lua_hash_str(u_char *src, size_t n) [% IF http_subsys %] static ngx_inline ngx_int_t -ngx_[% subsys %]_lua_set_content_type([% req_type %] *r) +ngx_[% subsys %]_lua_set_content_type([% req_type %] *r, + ngx_[% subsys %]_lua_ctx_t *ctx) { ngx_[% subsys %]_lua_loc_conf_t *llcf; + ctx->mime_set = 1; + llcf = ngx_[% req_subsys %]_get_module_loc_conf(r, ngx_[% subsys %]_lua_module); if (llcf->use_default_type && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) @@ -558,7 +561,7 @@ ngx_[% subsys %]_lua_get_flush_chain([% req_type %] *r, } -#if (nginx_version < 1011002) +#if defined(nginx_version) && nginx_version < 1011002 static ngx_inline in_port_t ngx_inet_get_port(struct sockaddr *sa) { diff --git a/src/subsys/ngx_subsys_lua_variable.c.tt2 b/src/subsys/ngx_subsys_lua_variable.c.tt2 index 457bffc..a44cbb3 100644 --- a/src/subsys/ngx_subsys_lua_variable.c.tt2 +++ b/src/subsys/ngx_subsys_lua_variable.c.tt2 @@ -11,305 +11,16 @@ #include "ddebug.h" -#include "ngx_[% subsys %]_lua_variable.h" #include "ngx_[% subsys %]_lua_util.h" -static int ngx_[% subsys %]_lua_var_get(lua_State *L); -static int ngx_[% subsys %]_lua_var_set(lua_State *L); - - [% IF http_subsys %] [% pool = 'r->pool' %] [% ELSIF stream_subsys %] [% pool = 'r->connection->pool' %] [% END %] -void -ngx_[% subsys %]_lua_inject_variable_api(lua_State *L) -{ - /* {{{ register reference maps */ - lua_newtable(L); /* ngx.var */ - - lua_createtable(L, 0, 2 /* nrec */); /* metatable for .var */ - lua_pushcfunction(L, ngx_[% subsys %]_lua_var_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ngx_[% subsys %]_lua_var_set); - lua_setfield(L, -2, "__newindex"); - lua_setmetatable(L, -2); - - lua_setfield(L, -2, "var"); -} - - -/** - * Get nginx internal variables content - * - * @retval Always return a string or nil on Lua stack. Return nil when failed - * to get content, and actual content string when found the specified variable. - * @seealso ngx_[% subsys %]_lua_var_set - * */ -static int -ngx_[% subsys %]_lua_var_get(lua_State *L) -{ - [% req_type %] *r; - u_char *p, *lowcase; - size_t len; - ngx_uint_t hash; - ngx_str_t name; -[% IF http_subsys %] -#if (NGX_PCRE) - u_char *val; - ngx_uint_t n; - LUA_NUMBER index; - int *cap; -#endif -[% END %] - - ngx_[% subsys %]_variable_value_t *vv; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - ngx_[% subsys %]_lua_check_fake_request(L, r); - -[% IF http_subsys %] -#if (NGX_PCRE) - if (lua_type(L, -1) == LUA_TNUMBER) { - /* it is a regex capturing variable */ - - index = lua_tonumber(L, -1); - - if (index <= 0) { - lua_pushnil(L); - return 1; - } - - n = (ngx_uint_t) index * 2; - - dd("n = %d, ncaptures = %d", (int) n, (int) r->ncaptures); - - if (r->captures == NULL - || r->captures_data == NULL - || n >= r->ncaptures) - { - lua_pushnil(L); - return 1; - } - - /* n >= 0 && n < r->ncaptures */ - - cap = r->captures; - - p = r->captures_data; - - val = &p[cap[n]]; - - lua_pushlstring(L, (const char *) val, (size_t) (cap[n + 1] - cap[n])); - - return 1; - } -#endif -[% END %] - - if (lua_type(L, -1) != LUA_TSTRING) { - return luaL_error(L, "bad variable name"); - } - - p = (u_char *) lua_tolstring(L, -1, &len); - - lowcase = lua_newuserdata(L, len); - - hash = ngx_hash_strlow(lowcase, p, len); - - name.len = len; - name.data = lowcase; - -[% IF http_subsys %] - vv = ngx_http_get_variable(r, &name, hash); -[% ELSIF stream_subsys %] - vv = ngx_stream_get_variable(r->session, &name, hash); -[% END %] - - if (vv == NULL || vv->not_found) { - lua_pushnil(L); - return 1; - } - - lua_pushlstring(L, (const char *) vv->data, (size_t) vv->len); - return 1; -} - - -/** - * Set nginx internal variable content - * - * @retval Always return a boolean on Lua stack. Return true when variable - * content was modified successfully, false otherwise. - * @seealso ngx_[% subsys %]_lua_var_get - * */ -static int -ngx_[% subsys %]_lua_var_set(lua_State *L) -{ - u_char *p, *lowcase, *val; - size_t len; - ngx_str_t name; - ngx_uint_t hash; - [% req_type %] *r; - int value_type; - const char *msg; - - ngx_[% subsys %]_variable_t *v; - ngx_[% subsys %]_variable_value_t *vv; - ngx_[% subsys %]_core_main_conf_t *cmcf; - - r = ngx_[% subsys %]_lua_get_req(L); - if (r == NULL) { - return luaL_error(L, "no request object found"); - } - - ngx_[% subsys %]_lua_check_fake_request(L, r); - - /* we skip the first argument that is the table */ - - /* we read the variable name */ - - if (lua_type(L, 2) != LUA_TSTRING) { - return luaL_error(L, "bad variable name"); - } - - p = (u_char *) lua_tolstring(L, 2, &len); - - lowcase = lua_newuserdata(L, len + 1); - - hash = ngx_hash_strlow(lowcase, p, len); - lowcase[len] = '\0'; - - name.len = len; - name.data = lowcase; - - /* we read the variable new value */ - value_type = lua_type(L, 3); - switch (value_type) { - case LUA_TNUMBER: - case LUA_TSTRING: - p = (u_char *) luaL_checklstring(L, 3, &len); - val = ngx_palloc([% pool %], len); - if (val == NULL) { - return luaL_error(L, "memory allocation error"); - } - - ngx_memcpy(val, p, len); - - break; - - case LUA_TNIL: - /* undef the variable */ - - val = NULL; - len = 0; - - break; - - default: - msg = lua_pushfstring(L, "string, number, or nil expected, " - "but got %s", lua_typename(L, value_type)); - return luaL_argerror(L, 1, msg); - } - - /* we fetch the variable itself */ - - cmcf = ngx_[% req_subsys %]_get_module_main_conf(r, ngx_[% subsys %]_core_module); - - v = ngx_hash_find(&cmcf->variables_hash, hash, name.data, name.len); - - if (v) { - if (!(v->flags & NGX_[% SUBSYS %]_VAR_CHANGEABLE)) { - return luaL_error(L, "variable \"%s\" not changeable", lowcase); - } - - if (v->set_handler) { - - dd("set variables with set_handler"); - - vv = ngx_palloc([% pool %], - sizeof(ngx_[% subsys %]_variable_value_t)); - if (vv == NULL) { - return luaL_error(L, "no memory"); - } - - if (value_type == LUA_TNIL) { - vv->valid = 0; - vv->not_found = 1; - vv->no_cacheable = 0; - vv->data = NULL; - vv->len = 0; - - } else { - vv->valid = 1; - vv->not_found = 0; - vv->no_cacheable = 0; - - vv->data = val; - vv->len = len; - } - -[% IF http_subsys %] - v->set_handler(r, vv, v->data); -[% ELSIF stream_subsys %] - v->set_handler(r->session, vv, v->data); -[% END %] - - return 0; - } - - if (v->flags & NGX_[% SUBSYS %]_VAR_INDEXED) { -[% IF http_subsys %] - vv = &r->variables[v->index]; -[% ELSIF stream_subsys %] - vv = &r->session->variables[v->index]; -[% END %] - - dd("set indexed variable"); - - if (value_type == LUA_TNIL) { - vv->valid = 0; - vv->not_found = 1; - vv->no_cacheable = 0; - - vv->data = NULL; - vv->len = 0; - - } else { - vv->valid = 1; - vv->not_found = 0; - vv->no_cacheable = 0; - - vv->data = val; - vv->len = len; - } - - return 0; - } - - return luaL_error(L, "variable \"%s\" cannot be assigned a value", - lowcase); - } - - /* variable not found */ - - 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", - lowcase, lowcase); -} - - -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_var_get([% req_type %] *r, u_char *name_data, size_t name_len, u_char *lowcase_buf, int capture_id, u_char **value, @@ -317,11 +28,13 @@ ngx_[% subsys %]_lua_ffi_var_get([% req_type %] *r, u_char *name_data, { ngx_uint_t hash; ngx_str_t name; +[% IF http_subsys %] #if (NGX_PCRE) u_char *p; ngx_uint_t n; int *cap; #endif +[% END %] ngx_[% subsys %]_variable_value_t *vv; @@ -335,6 +48,7 @@ ngx_[% subsys %]_lua_ffi_var_get([% req_type %] *r, u_char *name_data, return NGX_ERROR; } +[% IF http_subsys %] #if (NGX_PCRE) if (name_data == 0) { if (capture_id <= 0) { @@ -365,6 +79,7 @@ ngx_[% subsys %]_lua_ffi_var_get([% req_type %] *r, u_char *name_data, return NGX_OK; } #endif +[% END %] hash = ngx_hash_strlow(lowcase_buf, name_data, name_len); @@ -474,12 +189,20 @@ ngx_[% subsys %]_lua_ffi_var_set([% req_type %] *r, u_char *name_data, vv->len = value_len; } +[% IF http_subsys %] v->set_handler(r, vv, v->data); +[% ELSIF stream_subsys %] + v->set_handler(r->session, vv, v->data); +[% END %] return NGX_OK; } if (v->flags & NGX_[% SUBSYS %]_VAR_INDEXED) { +[% IF http_subsys %] vv = &r->variables[v->index]; +[% ELSIF stream_subsys %] + vv = &r->session->variables[v->index]; +[% END %] dd("set indexed variable"); @@ -534,7 +257,6 @@ nomem: *errlen = ngx_snprintf(errbuf, *errlen, "no memory") - errbuf; return NGX_ERROR; } -#endif /* NGX_LUA_NO_FFI_API */ /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_variable.h.tt2 b/src/subsys/ngx_subsys_lua_variable.h.tt2 deleted file mode 100644 index 81bab31..0000000 --- a/src/subsys/ngx_subsys_lua_variable.h.tt2 +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * Copyright (C) Xiaozhe Wang (chaoslawful) - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef _NGX_[% SUBSYS %]_LUA_VARIABLE_H_INCLUDED_ -#define _NGX_[% SUBSYS %]_LUA_VARIABLE_H_INCLUDED_ - - -#include "ngx_[% subsys %]_lua_common.h" - - -void ngx_[% subsys %]_lua_inject_variable_api(lua_State *L); - - -#endif /* _NGX_[% SUBSYS %]_LUA_VARIABLE_H_INCLUDED_ */ - -/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_worker.c.tt2 b/src/subsys/ngx_subsys_lua_worker.c.tt2 index 4c79a56..0e3c3d1 100644 --- a/src/subsys/ngx_subsys_lua_worker.c.tt2 +++ b/src/subsys/ngx_subsys_lua_worker.c.tt2 @@ -10,88 +10,9 @@ #include "ddebug.h" -#include "ngx_[% subsys %]_lua_worker.h" - - #define NGX_PROCESS_PRIVILEGED_AGENT 99 -static int ngx_[% subsys %]_lua_ngx_worker_exiting(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_worker_pid(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_worker_id(lua_State *L); -static int ngx_[% subsys %]_lua_ngx_worker_count(lua_State *L); - - -void -ngx_[% subsys %]_lua_inject_worker_api(lua_State *L) -{ - lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.worker. */ - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_worker_exiting); - lua_setfield(L, -2, "exiting"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_worker_pid); - lua_setfield(L, -2, "pid"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_worker_id); - lua_setfield(L, -2, "id"); - - lua_pushcfunction(L, ngx_[% subsys %]_lua_ngx_worker_count); - lua_setfield(L, -2, "count"); - - lua_setfield(L, -2, "worker"); -} - - -static int -ngx_[% subsys %]_lua_ngx_worker_exiting(lua_State *L) -{ - lua_pushboolean(L, ngx_exiting); - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_worker_pid(lua_State *L) -{ - lua_pushinteger(L, (lua_Integer) ngx_pid); - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_worker_id(lua_State *L) -{ -#if (nginx_version >= 1009001) - if (ngx_process != NGX_PROCESS_WORKER - && ngx_process != NGX_PROCESS_SINGLE) - { - lua_pushnil(L); - return 1; - } - - lua_pushinteger(L, (lua_Integer) ngx_worker); -#else - lua_pushnil(L); -#endif - return 1; -} - - -static int -ngx_[% subsys %]_lua_ngx_worker_count(lua_State *L) -{ - ngx_core_conf_t *ccf; - - ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, - ngx_core_module); - - lua_pushinteger(L, (lua_Integer) ccf->worker_processes); - return 1; -} - - -#ifndef NGX_LUA_NO_FFI_API int ngx_[% subsys %]_lua_ffi_worker_pid(void) { @@ -102,7 +23,7 @@ ngx_[% subsys %]_lua_ffi_worker_pid(void) int ngx_[% subsys %]_lua_ffi_worker_id(void) { -#if (nginx_version >= 1009001) +#if defined(nginx_version) && nginx_version >= 1009001 if (ngx_process != NGX_PROCESS_WORKER && ngx_process != NGX_PROCESS_SINGLE) { @@ -138,7 +59,7 @@ ngx_[% subsys %]_lua_ffi_worker_count(void) int ngx_[% subsys %]_lua_ffi_master_pid(void) { -#if (nginx_version >= 1013008) +#if defined(nginx_version) && nginx_version >= 1013008 if (ngx_process == NGX_PROCESS_SINGLE) { return (int) ngx_pid; } @@ -153,6 +74,8 @@ ngx_[% subsys %]_lua_ffi_master_pid(void) int ngx_[% subsys %]_lua_ffi_get_process_type(void) { + ngx_core_conf_t *ccf; + #if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 if (ngx_process == NGX_PROCESS_HELPER) { if (ngx_is_privileged_agent) { @@ -161,6 +84,15 @@ ngx_[% subsys %]_lua_ffi_get_process_type(void) } #endif + if (ngx_process == NGX_PROCESS_SINGLE) { + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + if (ccf->master) { + return NGX_PROCESS_MASTER; + } + } + return ngx_process; } @@ -190,4 +122,6 @@ ngx_[% subsys %]_lua_ffi_process_signal_graceful_exit(void) { ngx_quit = 1; } -#endif + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/subsys/ngx_subsys_lua_worker.h.tt2 b/src/subsys/ngx_subsys_lua_worker.h.tt2 deleted file mode 100644 index 7c2dc91..0000000 --- a/src/subsys/ngx_subsys_lua_worker.h.tt2 +++ /dev/null @@ -1,17 +0,0 @@ - -/* - * Copyright (C) Yichun Zhang (agentzh) - */ - - -#ifndef _NGX_[% SUBSYS %]_LUA_WORKER_H_INCLUDED_ -#define _NGX_[% SUBSYS %]_LUA_WORKER_H_INCLUDED_ - - -#include "ngx_[% subsys %]_lua_common.h" - - -void ngx_[% subsys %]_lua_inject_worker_api(lua_State *L); - - -#endif /* _NGX_[% SUBSYS %]_LUA_WORKER_H_INCLUDED_ */